Vulnerability Management

Inside a Vulnerability Management Platform: Architecture and Foundation

By PMAP Security Team 24 min read

Most buyers evaluate a vulnerability management tool by its features. They count connectors, look at dashboards, and ask whether it imports their scanner of choice. Those questions matter, yet they describe the surface. The harder question sits underneath. How is the product actually built, and does that foundation hold up when one team becomes ten, when one company becomes a holding with twenty subsidiaries, and when one scanner becomes thirty connectors feeding a single correlated record set?

This article opens the hood on PMAP and walks through its vulnerability management platform architecture. It is the technical companion to the rest of our pillar library. Where the other guides explain what each capability does, this one explains the shape that carries every capability: a Go modular monolith with roughly 500 REST endpoints across 48 backend domains, a strict multi-tenant invariant, a consistent API contract, an event-driven core, a cross-entity query builder, and a signed-license enforcement layer.

If you are a security platform architect, a platform administrator, or a technical decision maker comparing options, this is written for you. Every number and behavior below is drawn from how PMAP is built, not from marketing abstraction.

What “Platform” Really Means in Vulnerability Management

The word platform is overused. Many vulnerability tools call themselves platforms while shipping a single scanner with a reporting view bolted on top. That design works until the program grows. The moment a second scanner arrives, or a compliance team needs audit evidence, or an MSSP needs to isolate one client from another, the tool’s seams start to show.

A real platform is defined by what it can absorb without breaking. PMAP is positioned as an enterprise vulnerability management platform and a multi-vendor scan orchestrator covering Tenable, Qualys, Rapid7, DAST, SAST, SCA, ITSM, and CMDB sources. The defining word in that sentence is orchestrator. PMAP does not assume one source of truth for findings. It assumes many sources, then reconciles them into one correlated record set. That assumption shapes every architectural decision underneath.

A platform also has to host capabilities that do not naturally belong to each other. Asset inventory, finding triage, scan scheduling, runbook automation, report generation, and identity management are very different problems. They share data, but they have different lifecycles, different performance profiles, and different failure modes. The architecture’s job is to let each of those concerns evolve independently while still sharing one consistent contract. That balance is the whole story of how PMAP is built. If you want the end-to-end product story rather than the architecture, start with our pillar on the modern vulnerability management lifecycle.

The Modular Monolith Shape

PMAP ships as a single Go binary built from cmd/server, organized as a modular monolith. That phrase deserves unpacking because it is a deliberate choice with real consequences for buyers.

A monolith is one deployable unit. There is one process to run, one binary to ship, one set of logs to read. There is no service mesh to operate, no inter-service network hop on every read, and no distributed transaction problem to reason about. For a security product that has to be deployed inside customer infrastructure, including air-gapped environments, a single binary is an operational gift. It is simpler to install, simpler to upgrade, and simpler to reason about under incident pressure.

The modular half is what keeps that single binary from turning into an unmaintainable ball of code. Every business domain lives in its own package under internal/<domain>/, and each domain follows a strict four-file layout. The handler.go file owns the HTTP layer with Chi routes, request parsing, and response shaping. The service.go file owns business logic, including rules, state machines, orchestration, and validation. The repository.go file owns persistence with SQL through the pgx driver. The model.go file owns types, enums, state machines, and sentinel errors.

That discipline is not cosmetic. It means a security analyst’s mental model of how findings work maps directly to a single package. It means a change to scan scheduling does not accidentally reach into report generation. It means each domain can be read, reviewed, and tested in isolation. All domains are then wired together in cmd/server/main.go, where services are constructed, cross-domain dependencies are injected through setters and interfaces, and each handler is mounted under /api/v1.

The request flow is equally disciplined. A request travels from the Chi router through a middleware chain of authentication, then API-key resolution, then scope, then RBAC, before it reaches the handler, the service, and finally the repository and PostgreSQL. Every request passes through the same gates in the same order. That predictability is what makes the platform’s security guarantees auditable rather than aspirational.

The benefit for a buyer is concrete. A modular monolith gives you the maintainability advantages people associate with microservices, namely clear boundaries and independent evolution, without the operational tax of running a distributed system. You get one thing to deploy and many things to reason about separately.

The Tech Stack Behind PMAP

Architecture choices show their intent in the stack. PMAP is written in Go 1.26, which is a pragmatic choice for a security backend. Go compiles to a single static binary, has a mature concurrency model for the asynchronous work that vulnerability management demands, and produces predictable memory behavior under load.

The HTTP layer uses go-chi, a lightweight router that keeps the middleware chain explicit and readable. PostgreSQL 16 or later is the system of record, accessed through the jackc/pgx v5 driver in a sqlc-style. The schema is managed by golang-migrate with 435 embedded migration files, which means database evolution is versioned, repeatable, and shipped with the binary rather than applied by hand.

Redis backs ephemeral state such as MFA challenge tokens and rate-limiting counters. MinIO provides object storage for binary artifacts, namely finding attachments, project files, and generated reports. Authentication combines JWT through golang-jwt with LDAP and Active Directory support through go-ldap. Multi-factor authentication uses TOTP through pquerna/otp with QR generation. Durable workflows run on cschleiden/go-workflows, scheduling uses robfig/cron, and browser automation for DAST scanning uses chromedp. Document generation relies on go-pdf/fpdf and pdfcpu for PDF output and xuri/excelize for spreadsheet export.

The pattern across that list is restraint. Each dependency is a well-understood, widely used library that solves one problem. There is no exotic framework that locks the platform into a single vendor’s runtime. For a security buyer evaluating long-term risk, a conservative stack is a feature. It means the platform is easier to audit, easier to staff, and less likely to be hostage to a fragile dependency.

A Consistent API Contract Across 48 Domains

Forty-eight domains could easily mean forty-eight slightly different ways of paginating, filtering, and returning errors. That inconsistency is where most large APIs go wrong, and it is what makes them painful to integrate against. PMAP avoids it by defining the API contract centrally in the common package, and every domain conforms.

The base path is /api/v1. Every list response uses the same envelope: a data array paired with a pagination object that carries next_cursor, has_more, and total. Single-item responses use a data object. Errors use a consistent shape with an error field and a human-readable message. There are no ad-hoc JSON writes scattered across handlers. The frontend, and any integrator you employ, receives the same shapes from every endpoint.

Pagination is cursor-based by default, using id > $cursor ordering, and switches to offset pagination only when search or name-ordering is active. That hybrid is a deliberate correctness decision, because cursor-by-ID breaks under non-ID column sorting. The default page size is 20 and the hard ceiling is 100, with any excess silently clamped.

Search ordering is tuned for parity with the scanners customers already know. Free-text search uses an ILIKE substring match and deliberately avoids trigram similarity on names and IDs, because trigram matching produces false positives on exact identifiers. Results are ranked exact first, then prefix, then substring. Multi-value filters always use array membership rather than equality, so a multi-select filter behaves the way users expect. Every documented query parameter is parsed server-side, with a one-to-one match against the database and no hidden client normalization. Facets come from backend aggregates, each facet endpoint excludes its own filter, and list and facet endpoints share an identical WHERE clause so the counts never disagree with the rows.

This consistency is not just engineering hygiene. It is what makes PMAP integrable. When a contract is uniform across 48 domains, an integration team can learn it once and apply it everywhere. If you are building that integration layer across your stack, our pillar on the unified security integration layer covers the connector side of the same story.

Multi-Tenancy as a Non-Negotiable Invariant

Multi-tenancy is the architectural feature most often retrofitted, and retrofitting it is how data leaks happen. In PMAP it is built in from the foundation, and the language used internally to describe it is blunt: forgetting scope leaks cross-tenant data, and it is a non-negotiable invariant enforced in every domain.

The tenant boundary is the company, and a holding company with subsidiaries forms the hierarchy. Every list, export, and facet handler applies a ScopeFilter derived from the authenticated user’s resolved access. The filter carries three things: whether the user is unrestricted, which company IDs the user may see, and which project IDs the user may see. The default is deny. An empty list of allowed companies with the unrestricted flag set to false means zero access, not full access. Only the explicit unrestricted flag, reserved for platform administrators, signals see everything.

This default-deny posture matters because it fails safe. If a developer forgets to wire scope into a new query, the result is no rows, not every tenant’s rows. The repository layer short-circuits to a WHERE FALSE clause when access is denied. Cross-tenant ID access is rejected explicitly rather than silently filtered, so an attempt to reach another tenant’s finding by guessing its identifier is refused at the door.

The scope itself is resolved once per request by middleware that calls the RBAC service, writes the resolved scope context into the request, and makes every downstream check a zero-cost context lookup. If that resolver fails, the request returns 503 and fails closed, which makes an RBAC outage visible rather than turning it into a silent data exposure. For the operational side of multi-tenancy, including holding and subsidiary roll-up for MSSPs, see our pillar on multi-tenant vulnerability management. This section is about the invariant that makes that operational story safe.

The Advanced Query Builder and Global Search

A platform with 48 domains accumulates a lot of data, and no fixed set of list endpoints can anticipate every question a security analyst will need to ask. PMAP answers that with a dedicated query domain that serves two distinct functions: a global keyword search and a structured advanced query builder.

Global search is a single call that retrieves matching records across assets, findings, and projects, returning normalized results with entity type, title, subtitle, status, and severity. It is the omnisearch bar that lets an analyst jump to any record without knowing which list it lives in.

The advanced query builder is more powerful. It accepts a declarative grammar made of nested AND and OR condition groups, each condition carrying a field, an operator, and a value, with optional sorting and pagination. A group can contain both conditions and nested groups, which means an analyst can express an arbitrary boolean filter tree, not just a flat list of conditions. The builder supports four entity types, namely asset, finding, project, and company, and a fixed set of 13 operators ranging from equality and comparison through LIKE, IN, IS NULL, and the PostgreSQL array-contains operator for tag membership queries.

The interesting part for a security buyer is how the builder stays safe. A query builder that constructs SQL dynamically is a classic injection risk. PMAP closes that risk with a strict whitelist. Field names are validated against a per-entity-type allowlist, and only whitelisted column expressions ever reach the SQL string. Unknown fields are silently skipped, and operators are validated against a fixed set. Pagination is capped, with the advanced query limited to 500 rows and global search to 200. The result is the flexibility analysts want without the attack surface that ad-hoc query power usually introduces. There is also a companion asset version search that queries a JSONB column for software version strings, which supports vulnerability-by-version workflows directly.

Saved Filters and Views Across Ten Entities

The query builder answers one-off questions. The reality of vulnerability operations is that the same questions get asked every day. A triage lead always wants critical, open, SLA-breaching findings. An asset owner always wants their team’s high-risk assets. Asking those questions from scratch every morning is wasted effort.

PMAP solves the recurring case in two layers. The query domain lets users persist named advanced queries as saved views, scoped to the individual user, with create, list, and delete operations and ownership enforced on both read and delete so one user cannot touch another’s saved query. Separately, a dedicated savedfilter domain manages saved filter and view presets across 10 entity types. Together they turn a complex filter into a one-click view that travels with the user.

The architectural point is that saved views are not a frontend convenience hacked onto local storage. They are a first-class backend concern with their own persistence, their own ownership rules, and their own scoping. That is what lets a saved view behave consistently whether it is opened on a laptop, a second monitor, or a shared operations display. For the analyst-facing detail of how saved views speed daily work, our cluster on saved views goes deeper; this pillar establishes that they are part of the platform foundation rather than an afterthought.

The Admin Console and Platform Settings

Every platform needs a control plane, and in PMAP that plane is the admin domain. It owns the single global platform settings row that governs cross-cutting behavior across the whole system, and it is gated so that every admin route requires the platform administrator role.

That settings row is deliberately broad. It carries SMTP relay configuration for outbound email, LDAP and Active Directory configuration for authentication, white-label branding such as display name, logo, and primary color, storage and queue tuning, per-severity SLA deadlines, a three-tier escalation ladder, MFA enforcement policy, and a concurrent-session cap. One row, read by many downstream domains, governs the behaviors that have to be consistent platform-wide.

The write semantics are careful. Updates use pointer fields so that only fields actually present in the request generate a database SET clause. An empty string is treated as no change for sensitive credentials such as the SMTP password and the LDAP bind password, which means an admin cannot accidentally wipe a credential by submitting a partially filled form. Credentials are masked on read and only written when a non-empty value is supplied. The LDAP and SMTP panels each include a live test endpoint, so an admin can validate bind credentials or send a test email without persisting a broken configuration.

The admin console also surfaces operational truth. It hosts an infrastructure health dashboard that checks the database with latency, Redis reachability, object storage over HTTP, and the queue, then rolls those into per-component and overall status values. It lists configured integrations with a connectivity status. It exposes the activity log feed, a cursor-paginated read of every auditable action across the platform, with polymorphic entity names resolved server-side so the UI renders human-readable entries without extra lookups. A buyer evaluating operability should read that health and audit surface as the platform telling the truth about itself, which is exactly what you want under incident pressure. The compliance value of those dual audit trails is covered in our pillar on vulnerability management compliance and audit evidence.

Licensing With Ed25519 JWT and Quota Enforcement

Enterprise software has to enforce its own entitlements, and how a platform does that says a lot about its engineering maturity. PMAP uses a signed software license token as the authoritative source of truth for entitlements, and the enforcement is built into the architecture rather than bolted on.

A license is an Ed25519-signed JWT. The public key used to verify it is a compile-time constant baked into the binary, with no environment-variable or database override possible. That design closes a common tampering path, because there is no configuration knob an attacker could flip to accept a forged token. Validation is fully offline, which means air-gapped deployments are first-class rather than an exception. The token governs three dimensions: expiry and grace-period state, resource quotas such as the asset seat count, and feature flags carried in the claims.

Enforcement happens at two levels. A LicenseGate middleware sits on every authenticated write path, so POST, PUT, PATCH, and DELETE requests are blocked when the license is in a read-only, expired, revoked, or suspended state. Read paths through GET, HEAD, and OPTIONS always pass through, so operators retain full visibility into their data even when a license has hard-expired. That is a humane design choice. A lapsed license should never lock an operator out of seeing their own vulnerability data during an incident.

The quota side is enforced consistently. The asset seat count is checked on every asset create and import path, and the same check is applied by the scanner importers before they persist newly discovered assets, so scanner ingestion can never quietly exceed the licensed cap. The license state machine moves from unconfigured to valid, then to grace once past expiry but within the grace window, then to read-only once past that window, with revoked and suspended as immediate-block states the issuer can trigger. There is one deliberate exemption: the license installation endpoint itself is exempt from the gate, so a platform admin can always upload a fresh token to recover from an expired or revoked state. The provider refreshes its cached token every five minutes and refreshes immediately after an install, so a recovery takes effect at once rather than after a delay.

Observability: Metrics and Health

A platform you cannot see into is a platform you cannot trust in production. PMAP exposes observability through two complementary channels.

The first is a Prometheus metrics endpoint at /metrics, backed by in-process counters and histograms in a pmap_ namespace. Long-running background jobs emit their own metrics. The bulk rule re-evaluation engine, for example, tracks jobs started, jobs deduplicated, jobs completed, findings processed, and job duration. That instrumentation means an operations team can graph the platform’s internal work and alert on it using the same Prometheus and Grafana stack they already run.

The second is the dual audit trail. PMAP records typed security events synchronously and writes an asynchronous activity log, and both are surfaced through the admin console. The asynchronous activity log is handled by a buffered, batched queue that never silently drops an event. When its in-memory buffer is full, the queue falls back to a synchronous single-row insert rather than discarding the event, and it drains fully on shutdown. That guarantee exists specifically because audit completeness is a compliance requirement, not a best-effort nicety.

Between live infrastructure health, Prometheus metrics, and a guaranteed audit trail, the platform gives operators three independent ways to know what it is doing. For a technical buyer, that triad is a strong signal that the product was built to run in production rather than to demo well.

Event-Driven Foundations

Vulnerability management is full of long operations. Scans, imports, exports, and report generation can each take minutes, and none of them should block an HTTP request. PMAP handles that with an asynchronous, event-driven core where long operations are cancellable, resumable, and progress-aware.

At the center is an in-process publish-subscribe event bus with 34 event types. Dispatch is fully asynchronous, one goroutine per consumer, with panic isolation so a misbehaving consumer cannot take down the producer. Fourteen producer domains emit events, and four consumers act on them. The runbook domain consumes events to drive event-triggered automation across 16 triggers and 22 actions, with an optional durable workflow engine, cron scheduling, and a circuit breaker for reliability. The notification domain consumes events to fan out alerts across in-app, email, Slack, Teams, and webhook channels. The realtime domain bridges 15 event types to the browser over server-sent events, scoped to the user’s company so a live update never leaks across tenants. The audit domain bridges events into the activity log.

This event-driven shape is what lets PMAP feel live without coupling its domains together. A finding status change does not have to know that a runbook, a notification, a realtime push, and an audit entry all depend on it. It simply publishes an event, and the consumers react independently. That decoupling is the same principle as the modular monolith expressed at runtime. Domains stay independent, and the bus carries the coordination. The automation built on this foundation is the subject of our pillar on vulnerability management automation with rules and runbooks, and the live delivery side is covered in our pillar on real-time security operations.

How the Architecture Carries the Whole Product

It helps to see how all of this connects, because the architecture is not a collection of separate features. It is one dependency graph. Scanners flow into the integration domain, which is the largest single domain with 104 endpoints across 30 vendors covering VM scanners, DAST, SAST, SCA, ITSM, and CI/CD systems. Imports flow into the correlation engine, which deduplicates and normalizes findings through a four-case fingerprint pipeline. Findings flow through inline rule evaluation. Assets and scans feed the same record set, and projects, assessment runs, and campaigns sit above them.

On the other side of the graph, reporting, analytics, and dashboards consume findings and assets to produce KPIs and board-ready output. The company domain anchors tenancy and fans out into teams, RBAC, and scope. Everything sits on the common foundation that provides pagination, response envelopes, authorization, and middleware, and everything is gated by authentication, RBAC, and the license.

That single picture is the answer to the buyer’s question. The reason PMAP can absorb a new scanner, a new tenant, a new automation rule, or a new compliance requirement without breaking is that each of those lands in a bounded domain that shares one contract, one tenancy invariant, and one event bus with everything else. Growth lands as a new domain or a new connector, not as a rewrite. To trace any one of those capabilities in depth, the pillars on the vulnerability management lifecycle, multi-vendor scan orchestration, attack surface and asset inventory, security assessment management, vulnerability intelligence and enrichment, and risk analytics and reporting each take a single slice of this graph and follow it from intake to outcome.

Why the Architecture Is the Real Differentiator

Two products can show the same dashboard and behave very differently under load. The difference is the foundation, and the foundation is exactly what a feature demo hides. When you evaluate a vulnerability management platform, the architecture is the part that determines your three-year experience, not your first-week experience.

A modular monolith means you deploy one binary and still get clean internal boundaries, so upgrades stay simple while the codebase stays maintainable. A consistent API contract across 48 domains means your integration team learns the platform once. A non-negotiable multi-tenancy invariant means tenant isolation is a property of the architecture rather than a setting an administrator might forget. An offline-validated Ed25519 license means air-gapped deployment is normal rather than special. An event-driven core means automation, notification, realtime push, and audit all attach without coupling the domains that trigger them.

These properties do not show up on a feature checklist, yet they are what separate a platform that scales from a tool that stalls. The questions worth asking a vendor are about exactly these foundations. How do you enforce tenant isolation, and is it default-deny? What happens to writes when the license expires, and can operators still read their data? How does the API stay consistent as the product grows? PMAP has a concrete, source-grounded answer to each, and those answers are this article.

Frequently Asked Questions

What does “modular monolith” mean for a vulnerability management platform?

It means PMAP ships as a single Go binary that is internally organized into independent domain packages, each with a strict four-file layout for HTTP, business logic, persistence, and types. You get one thing to deploy and upgrade, with no service mesh or inter-service network hops, while still keeping clean internal boundaries between domains such as findings, scans, assets, and reporting. The practical effect is microservice-style maintainability without the operational cost of running a distributed system.

How many domains and endpoints does PMAP have?

PMAP is built as 48 backend domains exposing roughly 500 REST endpoints under a single /api/v1 base path. The largest single domain is integration, with 104 endpoints covering 30 vendor connectors. Every domain conforms to the same centrally defined API contract for pagination, response envelopes, and error shapes, so the surface stays consistent as the platform grows.

How does PMAP keep data isolated between tenants?

Multi-tenancy is enforced as a non-negotiable invariant. The tenant boundary is the company, and a holding with subsidiaries forms the hierarchy. Every list, export, and facet query applies a scope filter derived from the authenticated user, and the default is deny, so a missing scope returns no rows rather than another tenant’s rows. Cross-tenant identifier access is rejected explicitly, and the scope resolver fails closed with a 503 if it cannot resolve, which keeps an access-control outage visible instead of turning it into a leak.

What is the advanced query builder and is it safe from SQL injection?

The query builder is a declarative grammar of nested AND and OR condition groups across four entity types, supporting 13 operators including comparison, LIKE, IN, IS NULL, and PostgreSQL array-contains. It is injection-safe by design because field names are validated against a per-entity whitelist and only whitelisted column expressions ever reach the SQL string, while unknown fields are skipped and operators are checked against a fixed set. Users can persist named queries as saved views, and a separate saved-filter domain manages presets across 10 entity types.

How does software license enforcement work in PMAP?

A license is an Ed25519-signed JWT, validated fully offline against a public key compiled into the binary, so air-gapped deployments are fully supported and there is no configuration knob to accept a forged token. A license gate middleware blocks all write paths when the license is read-only, expired, revoked, or suspended, while read paths always pass through so operators keep visibility into their data. Asset seat quotas are enforced consistently on every create, import, and scanner-ingestion path, and the license install endpoint itself is exempt from the gate so an admin can always recover by uploading a fresh token.

Why does PMAP use an event-driven core?

Long operations such as scans, imports, exports, and report generation are asynchronous, cancellable, resumable, and progress-aware, so they never block an HTTP request. An in-process publish-subscribe bus with 34 event types fans work out to consumers for automation, multi-channel notification, server-sent-events realtime push to the browser, and the audit trail, each running independently with panic isolation. This decoupling means a single finding change can drive a runbook, an alert, a live update, and an audit entry without any of the producing domains knowing about the consumers.

Is PMAP built to scale from one team to many tenants?

Yes, and the reason is structural rather than promotional. Growth lands as a new bounded domain or a new connector that shares the same API contract, the same tenancy invariant, and the same event bus as everything already there, so adding a scanner, a tenant, an automation rule, or a compliance requirement does not force a rewrite. The same single binary that runs for one team runs for a holding company with many subsidiaries, with tenant isolation enforced in every domain by default.

author avatar
PMAP Security Team

Newsletter

Get the next writeup in your inbox

One short email when a new case writeup or detection deep dive ships. No marketing drip, no third-party tracking.