BoundaryGuard is currently pre-1.0. Only the main branch is supported.
| Component | Current version | Supported |
|---|---|---|
identityops-core-api |
0.1.0 | ✅ |
identityops-ingestion-api |
0.1.0 | ✅ |
identityops-incident-worker |
0.1.0 | ✅ |
identityops-webhook-worker |
0.1.0 | ✅ |
identityops-sdk |
0.1.0 | ✅ |
Older commits on main |
— | ❌ |
| Any fork not maintained here | — | ❌ |
Security fixes are applied to main only. There are no back-ported patch releases at this time.
Do not open a public GitHub issue for security vulnerabilities.
Use GitHub's private advisory mechanism:
- Navigate to the Security tab of this repository.
- Click Report a vulnerability.
- Complete the private advisory form with the information described in Reporting Vulnerabilities below.
Maintainers will acknowledge the report within 5 business days and aim to deliver a fix within 30 days of confirmation. If a coordinated public disclosure date is agreed, it will be respected.
TODO: Add a PGP public key or security email address here once a dedicated security contact is established.
Include the following in your report:
- Affected component — e.g.
core-api,worker-webhooks,sdk,dashboard,infra - Vulnerability class — e.g. authentication bypass, SSRF, privilege escalation, secret leakage
- Reproduction steps — a minimal sequence of commands or requests that demonstrate the issue
- Observed vs. expected behaviour — what the system does versus what it should do
- Potential impact — which users, tenants, or data are affected and how
- Suggested mitigation (optional) — if you have a proposed fix
Use the local dev stack (docker compose -f docker/docker-compose.dev.yml up -d) for reproduction. Do not test against production systems.
The following are in scope for responsible disclosure:
| Area | Examples |
|---|---|
| Authentication bypass | Forging a valid X-API-Key or Clerk JWT to gain tenant access |
| RBAC privilege escalation | Viewer-role caller executing freeze or admin operations |
| Tenant isolation failure | Reading or modifying incident data across tenant boundaries |
| HMAC signature bypass | Submitting unsigned or invalidly signed events to ingestion-api that are accepted |
| Blocklist bypass in the SDK middleware | A revoked session passing the BlocklistMiddleware check |
| Audit chain manipulation | Writing or modifying audit_events or mitigation_logs rows in a way that passes chain verification |
| Secret leakage | Credentials, tokens, or plaintext secrets exposed in API responses, logs, or error messages |
| Infrastructure misconfiguration | Public exposure of private-subnet services; IAM policy over-permissions |
- Vulnerabilities that require physical access to AWS infrastructure
- Social engineering of maintainers
- Denial-of-service attacks requiring volumetric capacity beyond a single server
- Issues in dependencies that have no published fix (
ignore-unfixedis set in Trivy) TODO-marked items inROADMAP.mdthat are not yet implemented
The following summarises how secrets are handled in this project. Contributors must follow these expectations.
| Secret | Storage (dev) | Storage (production) |
|---|---|---|
HMAC_SECRET |
.env file (gitignored) |
AWS Secrets Manager → ECS task secret mapping |
| SDK API key (plaintext) | Returned once at generation; never stored | — |
| SDK API key (hash) | PostgreSQL tenants.sdk_api_key_hash (SHA-256) |
RDS (encrypted at rest) |
CLERK_SECRET_KEY |
.env file (gitignored) |
Secrets Manager → ECS env |
Auth0 client_id / client_secret / domain |
.env file (gitignored) |
Per-tenant AES-256-GCM encrypted JSONB in tenants.provider_credentials_enc |
webhook_secret |
.env file (gitignored) |
AES-256-GCM encrypted in tenants.webhook_secret_enc (decrypted only in worker-webhooks) |
DATABASE_URL |
.env file (gitignored) |
Secrets Manager → ECS task secret |
REDIS_URL |
.env file (gitignored) |
Secrets Manager → ECS task secret |
Rules for contributors:
- Never commit secrets.
.envfiles are gitignored..env.examplecontains only non-secret placeholder values. Gitleaks scans the full git history on every push — a committed secret will block the CI pipeline. - Never log secrets. Do not pass credentials, tokens, or hashed keys into log statements. API key values must not appear in exception messages.
- Store only hashes, not plaintexts. SDK API keys are stored as SHA-256 hex digests. Authentication uses
hmac.compare_digestto prevent timing oracles. - Use
rediss://in production. The core-api startup validator (_enforce_production_tls) hard-fails ifAPP_ENV=productionandREDIS_URLdoes not begin withrediss://. - Use
DB_SSL_MODE=requireor higher in production. Valuesdisable,allow, andpreferare rejected at startup.
Dependencies are audited continuously through the CI security pipeline (.github/workflows/security.yml):
| Tool | Scope | Fail threshold | Frequency |
|---|---|---|---|
| Trivy (filesystem) | All repo files + deps | CRITICAL or HIGH CVE | Every push, PR, nightly |
| Trivy (image) | 4 service container images | CRITICAL CVE | Every push to main/develop |
| pip-audit | Python deps for all 4 services | Any known vulnerability | Every push, PR, nightly |
| npm audit | Dashboard Node.js deps | CRITICAL level | Every push, PR, nightly |
| GitHub Dependency Review | Newly introduced deps in PRs | CRITICAL severity | Every PR to main/develop |
Policy:
- Any dependency introducing a CRITICAL CVE will block the CI security gate and must be resolved before merging.
- HIGH-severity CVEs are surfaced in Trivy filesystem scans and will block CI (
exit-code: "1"). - Unfixed CVEs (no upstream patch exists) are suppressed in
.trivyignorewith a documented justification comment; this file is reviewed on each PR. - GPL-3.0 and AGPL-3.0 licensed dependencies are automatically blocked by the GitHub Dependency Review action.
Maintainers review nightly scan results at the start of each working week.
TODO: Define a maximum SLA for remediating HIGH-severity CVEs once the team grows beyond a single maintainer.
The full threat model is maintained in THREAT_MODEL.md (classified internal/security-sensitive). The following is a public summary.
BoundaryGuard enforces defence-in-depth across six trust boundaries:
| Boundary | Controls |
|---|---|
| Internet → ALB | AWS WAF v2 (OWASP Top 10, rate limit 2 000 req/5 min per IP, IP reputation), TLS 1.3, HTTP→HTTPS redirect |
| ALB → ECS | Security groups restricting source to ALB only; ECS tasks in private VPC subnets with no public IPs |
| ECS → RDS | PostgreSQL SSL verify-full; security group allowing ECS source only |
| ECS → Redis | TLS + AUTH token; rediss:// enforced in production; security group allowing ECS source only |
| ECS → AWS APIs | IAM Task Role with minimal SQS send/receive/delete permissions; Secrets Manager resource policy |
| Human → Dashboard | Clerk JWT (RS256, 60 s expiry); auth.protect() enforced on all dashboard routes |
| Caller | Mechanism | Scope |
|---|---|---|
| Human operator (dashboard) | Clerk JWT — RS256, JWKS-verified, 60 s expiry, tenant_id claim required |
Tenant-scoped; role from DB |
| Machine caller (SDK) | X-API-Key — SHA-256 digest compared with hmac.compare_digest |
Tenant-scoped; non-role identity |
| Ingestion sender | X-IdentityOps-Signature — HMAC-SHA256, replay window 300 s |
Provider-level |
- RBAC: Three-tier role hierarchy (
viewer,responder,security_admin) enforced server-side on all management and action endpoints. Viewer-role callers cannot execute freeze operations. - Tenant isolation: All database queries include a
tenant_idpredicate derived from the verified Clerk JWT claim. The query parameter on the SSE stream is validated against the JWT claim — mismatches return HTTP 403. - Idempotent freeze: Account freeze writes an audit event and revokes token families atomically in a single serialisable PostgreSQL transaction.
Idempotency-Key(UUID v4, SHA-256 hashed in Redis, 24 h TTL) prevents double-execution. - Tamper-evident audit chain:
audit_eventsandmitigation_logsuse a SHA-256 linked hash chain.REVOKE UPDATE, DELETEis granted to the application user — the database role cannot modify committed rows. - Immutable audit storage: CloudTrail multiregion with log file validation; S3 Object Lock COMPLIANCE (365 days); S3 deletion protection.
- Read-only container filesystem:
readonlyRootFilesystem: truein all ECS task definitions.
The following limitations are accepted and documented. They do not have immediate mitigations but are tracked for future resolution.
| ID | Limitation | Impact | Status |
|---|---|---|---|
| AR-01 | If Redis is unavailable, idempotency middleware fails open — a freeze request may execute twice | Duplicate audit event; functionally idempotent (second freeze revokes 0 families) | Accepted; fail-open is preferred over blocking incident response |
| AR-02 | SDK X-API-Key tokens have no expiry — exfiltrated keys can be replayed indefinitely |
High if key is leaked; requires manual rotation | Mitigated by WAF rate-limiting and CloudTrail monitoring; rotation workflow documented in OPERATIONS.md |
| AR-03 | Token family issued after a freeze begins may escape the initial revocation | New session is active on a frozen account until a second freeze or TTL expiry | Mitigated by short token TTL (default 24 h) and GuardDuty anomaly re-detection |
| AR-04 | A single authenticated operator can hold an unlimited number of concurrent SSE connections | ECS memory pressure under extreme conditions | Accepted for multi-tab SOC workflows; ECS memory alarms alert on saturation |
| AR-05 | Clerk JWKS public key compromise would allow JWT forgery | Critical; complete authentication bypass | Mitigated by Clerk's HSM key management and short JWT TTL (60 s) |
| AR-06 | Concurrent worker-incident instances may both create a new incident for the same account |
Duplicate open incidents for the same event | Known edge case at MVP scale; addressed by a partial unique index planned in ROADMAP.md |
Review this register after any significant architecture change or quarterly, whichever is sooner.