Instruction file imported from ErnestoCubo/DomainRaptor (
.github/instructions/security.instructions.md). Copyright stays with the author.
Security rules
Owner: security-officer. These rules are blocking. security-officer
runs in parallel with qa-reviewer and devops-engineer on every PR.
Code hot paths (HARD RULE)
| Risk | Forbidden | Required |
|---|---|---|
| SSRF | httpx.get(f"https://{user_input}") |
Validate via core.validators first |
| SQL injection | f-string SQL, text(f"SELECT … {x}") |
SQLAlchemy Core with bound params |
| Path traversal | open(f"{dir}/{user_input}") |
pathlib.Path + .resolve() + boundary check |
| YAML | yaml.load |
yaml.safe_load |
| Subprocess | shell=True, string command |
[argv], shell=False, check=True, timeout=N |
| Pickle | pickle.loads of external data |
json / explicit schema |
| TLS | verify=False, _create_unverified_context |
Default verification, pinned CA if needed |
Secrets (HARD RULE)
- API keys load from env or
~/.config/domainraptor/config.yamlonly. - Never log secrets. Use
utils.redact()on any structure that might containAuthorization,X-Api-Key, cookies, tokens. detect-secretsbaseline (.secrets.baseline) must stay current.- CI secrets: GitHub Secrets + OIDC. No PAT in env. No
${{ secrets.X }}printed viaecho.
Dependencies (HARD RULE)
uv pip auditclean forhigh/critical.mediumneeds a comment in PR with remediation date.lowdocumented inSECURITY.md.- Pin transitive CVE-prone deps in
pyproject.toml[tool.uv.constraints]when no upstream fix.
Bandit (HARD RULE)
uv run bandit -r src/→ zeromedium/high.lowrequires# nosec B### -- reason(specific code, real reason).- No blanket
# nosecever.
Logging safety (HARD RULE)
- Forbidden:
logger.info("response: %s", response.content). - Forbidden:
logger.debug("headers: %s", dict(headers)). - Required: log only metadata (status, length, redacted host).
IaC (when introduced)
checkov+trivy fsmandatory in CI.- Dockerfile: multi-stage, non-root user, base pinned by digest,
HEALTHCHECKdefined,.dockerignorepresent. - Terraform: no inline secrets, state in encrypted backend, drift check in CI.
- Kubernetes:
securityContextwithrunAsNonRoot: true,readOnlyRootFilesystem: true, no:latestimages.
Threat-modeling cadence
security-officer plan runs at sprint kickoff for:
- New external integrations (
discovery/*_client.py,enrichment/*). - Storage backend changes.
- Any task touching
core/config.pyor auth/secret loading. - Any PR introducing
infra/,Dockerfile,*.tf.
Output: T###-sec-*.md task in current sprint with STRIDE summary.
Vulnerability disclosure
SECURITY.md at repo root describes reporting channel. security-officer
owns updates to it.