14 KiB
Secret Leak Detection (Scanner Operations)
Status: IMPLEMENTED (2026-01-04). Feature is production-ready.
Audience: Scanner operators, Security Guild, Docs Guild, Offline Kit maintainers.
Implementation Status
| Component | Status | Sprint (Archived) |
|---|---|---|
StellaOps.Scanner.Analyzers.Secrets plugin |
IMPLEMENTED | SPRINT_20260104_002 |
| Rule bundle infrastructure | IMPLEMENTED | SPRINT_20260104_003 |
Policy DSL predicates (secret.*) |
IMPLEMENTED | SPRINT_20260104_004 |
| Offline Kit integration | IMPLEMENTED | SPRINT_20260104_005 |
| Configuration API | IMPLEMENTED | SPRINT_20260104_006 |
| Alert Integration | IMPLEMENTED | SPRINT_20260104_007 |
| UI Components | IMPLEMENTED | SPRINT_20260104_008 |
| Surface.Secrets (credential delivery) | IMPLEMENTED | N/A (already complete) |
Note: All secret leak detection components are now fully implemented and production-ready. Surface.Secrets (operational credential management) remains a separate, independent feature.
1. Scope & goals
- Introduce the
StellaOps.Scanner.Analyzers.Secretsplug-in, which executes deterministic rule bundles against layer content during scans. - Ensure every finding is reproducible: rule bundles are DSSE-signed, versioned, and shipped with the Offline Kit.
- Surface policy-ready evidence (
secret.leak) so tenants can enforce block/warn flows usingstella-dsl@1predicates. - Preserve sovereignty: rule bundles install locally, no outbound telemetry, masking is enforced before data leaves the worker.
2. Prerequisites
| Requirement | Notes |
|---|---|
| Analyzer binaries | Deploy StellaOps.Scanner.Analyzers.Secrets alongside Scanner Worker (packaged with the standard container images). |
| Surface libraries | Surface.Secrets, Surface.Validation, and Surface.Env must already be configured (see surface-secrets.md). |
| Experimental flag | Enable scanner.features.experimental["secret-leak-detection"] = true on both WebService and Worker. |
| Policy readiness | Import predicates from docs/modules/policy/secret-leak-detection-readiness.md into tenant policy packs. |
| Offline Kit | Update to an Offline Kit that includes offline/rules/secrets/<release>/ before enabling production scans. |
3. Rule bundle lifecycle
Rule bundles ship in the Export Center / Offline Kit under offline/rules/secrets/<release>/.
| File | Purpose | Notes |
|---|---|---|
secrets.ruleset.manifest.json |
Lists rule IDs, versions, severity defaults, and hash digests. | Consume during policy drift audits. |
secrets.ruleset.rules.jsonl |
Newline-delimited definitions (regex/entropy metadata, masking hints). | Loaded by the analyzer at startup. |
secrets.ruleset.dsse.json |
DSSE envelope (HMAC-SHA256 signature). | Verify before distributing bundles. |
3.1 Creating custom bundles
Organizations can create custom rule bundles with additional detection patterns:
# Create a bundle from rule definition files
stella secrets bundle create \
--output ./bundles/custom-2026.01 \
--bundle-id custom.secrets.ruleset \
--version 2026.01 \
--rules ./custom-rules/*.json
# Create and sign in one step
stella secrets bundle create \
--output ./bundles/custom-2026.01 \
--bundle-id custom.secrets.ruleset \
--version 2026.01 \
--rules ./custom-rules/*.json \
--sign \
--key-id my-org-secrets-signer \
--shared-secret-file /path/to/signing.key
Rule definition files must follow the JSON schema:
{
"id": "myorg.secrets.internal-api-key",
"version": "1.0.0",
"name": "Internal API Key",
"description": "Detects internal API keys with MYORG prefix",
"type": "regex",
"pattern": "MYORG_[A-Z0-9]{32}",
"severity": "high",
"confidence": "high",
"keywords": ["MYORG_"],
"filePatterns": ["*.env", "*.yaml", "*.json"],
"enabled": true
}
Rule ID requirements:
- Must be namespaced (e.g.,
myorg.secrets.rule-name) - Must start with lowercase letter
- May contain lowercase letters, digits, dots, and hyphens
3.2 Verifying bundles
Verify bundle integrity and signature before deployment:
# Basic verification (checks SHA-256 integrity)
stella secrets bundle verify \
--bundle ./bundles/2026.01
# Full verification with signature check
stella secrets bundle verify \
--bundle ./bundles/2026.01 \
--shared-secret-file /path/to/signing.key
# Verify with trusted key list
stella secrets bundle verify \
--bundle ./bundles/2026.01 \
--shared-secret-file /path/to/signing.key \
--trusted-key-ids stellaops-secrets-signer,my-org-signer
For air-gapped environments, use the local verification mode (no network calls):
stella secrets bundle verify \
--bundle ./bundles/2026.01 \
--shared-secret-file /path/to/signing.key \
--skip-rekor
Alternatively, use stella excititor verify for Attestor-based verification:
stella excititor verify \
--attestation offline/rules/secrets/2026.01/secrets.ruleset.dsse.json \
--digest $(sha256sum offline/rules/secrets/2026.01/secrets.ruleset.rules.jsonl | cut -d' ' -f1)
3.3 Deploying bundles
Once verified, copy the bundle to the worker:
/opt/stellaops/plugins/scanner/analyzers/secrets/
|- secrets.ruleset.manifest.json
|- secrets.ruleset.rules.jsonl
|- secrets.ruleset.dsse.json
Restart the worker so the analyzer reloads the updated bundle. Bundles are immutable; upgrading requires replacing all three files and restarting.
See secrets-bundle-rotation.md for rotation procedures and rollback instructions.
4. Enabling the analyzer
-
Toggle the feature flag (WebService + Worker):
scanner: features: experimental: secret-leak-detection: true(Environment alternative:
SCANNER__FEATURES__EXPERIMENTAL__secret-leak-detection=true.) -
Configure retention (WebService):
scanner: storage: migrations: - Scanner.Analysis.SecretFindingsTtlThe migration adds
secretFindingsrecords toScanAnalysisStorewith the standard TTL (default 90 days). Adjust PostgreSQL retention policy via the deployment overlay if longer retention is required. -
Activate policy ingestion (WebService):
scanner: runtime: enableSecretFindings: true(Experimental builds gate secret evidence behind this toggle to avoid surprising downstream consumers.)
-
Roll scanner hosts. Apply the configuration, roll WebService first, then Workers. Verify the startup logs contain
SecretsAnalyzerHostandSecretLeakDetection: Enabled.
5. Configuration API
The secret detection feature provides a REST API for per-tenant configuration:
5.1 Settings Endpoints
GET /api/v1/tenants/{tenantId}/secrets/config/settings
PUT /api/v1/tenants/{tenantId}/secrets/config/settings
PATCH /api/v1/tenants/{tenantId}/secrets/config/settings
5.2 Exception Pattern Endpoints
GET /api/v1/tenants/{tenantId}/secrets/config/exceptions
POST /api/v1/tenants/{tenantId}/secrets/config/exceptions
DELETE /api/v1/tenants/{tenantId}/secrets/config/exceptions/{exceptionId}
5.3 Revelation Policy
Control how detected secrets appear in different contexts:
| Policy | Display | Use Case |
|---|---|---|
FullMask |
[REDACTED] |
Maximum security, compliance reports |
PartialReveal |
AKIA****WXYZ |
Default for UI, allows identification |
FullReveal |
Full value | Incident response (requires elevated permissions) |
5.4 Alert Configuration
Configure alerting for secret findings via the Notify service:
- Destinations: Slack, Teams, Email, Webhook, PagerDuty
- Rate Limiting: Max alerts per scan (default: 10)
- Deduplication: 24-hour window to prevent duplicate alerts
- Severity Routing: Route critical findings to different channels
6. Policy patterns
The analyzer emits secret.leak evidence with the shape:
{
"ruleId": "stellaops.secrets.aws-access-key",
"ruleVersion": "2026.01.0",
"severity": "high",
"confidence": "high",
"file": "/app/config.yml",
"line": 42,
"mask": "AKIA********B7",
"bundleId": "secrets.ruleset",
"bundleVersion": "2026.01"
}
Policy DSL helpers introduced with this release:
| Helper | Description |
|---|---|
secret.hasFinding(ruleId?, severity?, confidence?) |
Returns true if any finding matches the filter. |
secret.bundle.version(requiredVersion) |
Ensures the active bundle meets or exceeds a version. |
secret.match.count(ruleId?) |
Returns the number of findings (useful for thresholds). |
secret.mask.applied |
Returns true if masking was successfully applied. |
secret.path.allowlist(patterns) |
Returns true if all findings are in allowed paths. |
Sample policy (policies/secret-blocker.stella):
policy "Secret Leak Guard" syntax "stella-dsl@1" {
metadata {
description = "Block high-confidence secret leaks"
tags = ["secrets","compliance"]
}
rule block_high_confidence priority 10 {
when secret.hasFinding(severity: "high", confidence: "high")
then escalate to "block";
because "High severity secret leak detected";
}
rule require_current_bundle priority 5 {
when not secret.bundle.version("2026.01")
then warn message "Secret leak bundle out of date";
}
}
Tenants that prefer staged rollout can downgrade low-confidence findings:
rule low_confidence_warn priority 20 {
when secret.hasFinding(confidence: "low")
then annotate decision.notes := "Investigate masked payload";
else ignore;
}
7. UI Components
The secret detection UI is available at /tenants/{tenantId}/secrets/:
7.1 Settings Page
- General Tab: Enable/disable detection, revelation policy, rule categories
- Exceptions Tab: Manage allowlist patterns for false positive suppression
- Alerts Tab: Configure alert destinations and thresholds
7.2 Findings List
- Filterable by severity, status, rule category
- Masked value display with conditional reveal
- Pagination and export support
7.3 Exception Manager
- Create/edit/delete exception patterns
- Regex validation with test mode
- Expiration dates for temporary exceptions
8. Observability & reporting
- Metrics:
scanner.secret.finding_total{tenant,ruleId,severity,confidence}increments per finding. Add Prometheus alerts for spikes. - Logs:
SecretsAnalyzerHostlogs bundle version on load and emits warnings when masking fails (payload never leaves memory). - Traces: Each analyzer run adds a
scanner.secrets.scanspan with rule counts and wall-clock timing. - Reports / CLI: Scan reports include a
secretFindingsarray; CLI diff/export surfaces render masked snippets plus remediation guidance.
9. Troubleshooting
| Symptom | Resolution |
|---|---|
| Analyzer disabled at startup | Confirm feature flag and bundle files exist; check plugins/scanner/analyzers/secrets permissions (640). |
| No findings despite seeded secrets | Ensure bundle hash matches manifest. Run worker with --secrets-trace (debug build) to log matched rules locally. |
| Policy marks findings as unknown | Upgrade tenant policies to include secret.* helpers; older policies silently drop the namespace. |
| Air-gapped verification fails | Ensure STELLA_ATTESTOR_URL points to the Offline Kit Attestor mirror and rerun stella excititor verify --attestation <file> --digest <sha256>. |
| Signature verification failed | Check shared secret matches signing key. Verify DSSE envelope exists and is not corrupted. See signature troubleshooting below. |
| Bundle integrity check failed | Rules file was modified after signing. Re-download bundle or rebuild from sources. |
| Key not in trusted list | Add signer key ID to --trusted-key-ids or update scanner.secrets.trustedKeyIds configuration. |
9.1 Signature verification troubleshooting
"Signature verification failed" error:
-
Verify the shared secret is correct:
# Check secret file exists and is readable cat /path/to/signing.key | wc -c # Should output the key length (typically 32-64 bytes for base64-encoded keys) -
Check the DSSE envelope format:
# Verify envelope is valid JSON jq . ./bundles/2026.01/secrets.ruleset.dsse.json -
Confirm manifest matches envelope payload:
# The envelope payload (base64url-decoded) should match the manifest content # excluding the signatures field
"Rules file integrity check failed" error:
-
Recompute the SHA-256 hash:
sha256sum ./bundles/2026.01/secrets.ruleset.rules.jsonl -
Compare with manifest:
jq -r '.integrity.rulesSha256' ./bundles/2026.01/secrets.ruleset.manifest.json -
If hashes differ, the rules file was modified. Re-download or rebuild the bundle.
"Bundle is not signed" error:
The bundle was created without the --sign flag. Either:
- Rebuild with signing:
stella secrets bundle create ... --sign --key-id <key> - Skip signature verification:
--skip-signature-verification(not recommended for production)
10. References
docs/modules/policy/secret-leak-detection-readiness.mddocs/benchmarks/scanner/deep-dives/secrets.mddocs/modules/scanner/design/surface-secrets.mddocs/ARCHITECTURE_OVERVIEW.md- Runtime inventory (Scanner)- Secrets Bundle Rotation