Structured, portable, machine-readable security context for code repositories.
SARIF (2020, OASIS) standardized scanner output. This spec standardizes scanner input — the security-relevant context that every scanner rediscovers on every run.
Every security scanner asks the same questions about your code: Is this deployed? Where? Is it public-facing? Who owns it? Is this CVE actually reachable? None of them remember the answers.
The result is a staggering amount of repeated work — by humans and by AI agents:
- Triaging the same false positives across Snyk, Trivy, Semgrep, and CodeQL because each has its own ignore file format
- Re-explaining deployment context to every new tool, every scan, every quarter
- Burning tokens and compute as AI agents re-discover "this runs on Kubernetes behind a WAF" from scratch on every invocation
- Duplicating severity adjustments — manually downgrading the same CVE in four dashboards because no scanner knows it's behind a VPN
- Wasting engineering hours answering "is this actually exploitable?" when the context to answer that question already exists — just not in a format any scanner can read
A single .security-context.yaml eliminates this entire class of repetitive work. Write it once. Every scanner, every AI agent, every triage workflow reads it. Context stops being a discovery problem and becomes a lookup.
Every field must either change a security finding or eliminate a security-relevant discovery step.
A field that doesn't adjust a severity, waive a finding, or eliminate a step a scanner needs to assess a vulnerability doesn't belong in v1.0.
Drop a .security-context.yaml in your repo root. Scanners consume it to:
- Adjust severity — a vulnerability behind a VPC and WAF is less severe than one on the public internet
- Suppress false positives — CWE-level suppression with rationale, portable across any scanner
- Route ownership — findings in vendored paths go to the right team
- Assess blast radius — cross-repo trust relationships reveal what compromising repo A grants over system B
- Skip discovery — no more re-discovering "is this deployed?", "is this ephemeral?", "who owns this?" on every scan
# .security-context.yaml
metadata:
schema_version: "1.0"
repo: org/my-service
status: production
service_tier: standard
owner:
team: platform-team
security_properties:
exposure: internal
platform: kubernetes
ephemeral: false
network_isolated: true| Section | Purpose |
|---|---|
metadata |
Identity, lifecycle, classification, ownership scope |
security_properties |
Flat security-relevant deployment facts |
prerequisites |
What an attacker must already have |
relationships |
Cross-repo blast radius and trust boundaries |
dependencies |
Unreachable CVEs and base image context |
accepted_risks |
Intentional design tradeoffs with expiry and audit trail |
scanning_directives |
Finding modifiers — suppress, prioritize, false positive patterns |
This spec complements existing standards — it does not replace them:
| Standard | Overlap | Relationship |
|---|---|---|
| SARIF (OASIS) | None — different direction | SARIF = output, this = input |
| VEX (OASIS) | dependencies.known_unreachable, accepted_risks |
Entries MAY reference VEX document IDs |
| OSCAL SSP (NIST) | Conceptual (system security context) | OSCAL is compliance-oriented; this is developer-maintained |
| CycloneDX (v1.5+) | Build environment metadata | Complementary; some overlap |
| OpenSSF Security Insights | metadata.status, metadata.owner |
Complementary repo-level metadata |
| Scanner ignore files | .trivyignore, .snyk, .semgrepignore |
Per-scanner, not portable. scanning_directives is portable. |
├── spec/
│ ├── security-context-latest.md # Symlink → current version
│ └── versions/
│ └── security-context-v1.0.md # Normative specification (v1.0)
├── decisions/
│ ├── TEMPLATE.md # Proposal template
│ ├── proposals/ # Active proposals
│ ├── accepted/ # Accepted decisions
│ └── rejected/ # Rejected with rationale
├── schema/
│ └── security-context-v1.schema.json # JSON Schema for IDE/tooling
├── tools/
│ └── validate/ # Go reference validator (single binary)
├── skills/
│ └── generate-security-context/ # Agent skill (agentskills.io)
│ ├── SKILL.md # Multi-phase directed workflow
│ ├── scripts/scan.go # Deterministic repo scanner
│ └── references/ # Phase instructions
├── examples/ # 8 example files (minimal → data-pipeline)
├── .github/
│ ├── rulesets/ # Branch and tag protection rules
│ ├── workflows/ci.yml # CI: two-tier (fast gate + cross-platform)
│ ├── ISSUE_TEMPLATE/ # Bug, feature, proposal templates
│ └── CODEOWNERS
├── Makefile
├── AGENTS.md
├── CONTRIBUTING.md
├── SECURITY.md
├── CODE_OF_CONDUCT.md
├── CHANGELOG.md
└── LICENSE # Apache-2.0
make help # Show all targets
make check # Full CI: lint + fmt-check + test + validate
make validate # Validate all examples
make validate-file FILE=.security-context.yaml
make scan REPO=/path/to/repo # Scan a repo for detectable security properties
make current # Show current spec version
make versions # List all spec versions
make release VERSION=1.1 # Snapshot current spec as a new version
make proposal NAME=add-runtime-details # Create a new proposal
make proposals # List proposals by status
make accept PROPOSAL=add-runtime-details
make reject PROPOSAL=add-runtime-detailsThe reference validator is a single Go binary with one dependency (gopkg.in/yaml.v3). Validation logic is Go structs — no JSON Schema library at runtime.
make build
./tools/validate/security-context-validate .security-context.yaml
# OK: .security-context.yaml is validThe JSON Schema (schema/security-context-v1.schema.json) ships alongside for IDE autocompletion and CI tooling that already consumes JSON Schema.
To consume .security-context.yaml:
- Look for
.security-context.yamlin the repository root - Parse YAML; validate
metadata.schema_versionis"1.0" - Use
security_propertiesto adjust finding severity - Use
prerequisitesto assess attacker cost - Use
scanning_directives.suppressto filter findings — but report what was suppressed - Use
accepted_risksto annotate findings with existing risk acceptances — flag expired ones - Use
relationshipsfor cross-repo blast radius analysis
Trust model: The file is maintained by the team whose code is being scanned. Treat it as a declaration of context, not a grant of authority. Your scanner decides how much weight to give each field.
Apache-2.0