| name | safety-checks |
| description | Security auditing with graph-persisted concerns. STRIDE-based threat analysis writing SecurityConcern nodes linked to dependencies, crates, and modules. Enables supply chain and security posture queries.
|
| argument-hint | [audit scope] |
Purpose
Security auditing with graph persistence. Every finding becomes a
:SecurityConcern node linked to affected dependencies, crates, and modules.
Auto-triggers as background knowledge during development. When invoked
manually, performs a full codebase audit using STRIDE-based threat analysis
with all findings persisted to the graph for cross-session tracking.
When NOT to use: Pure internal logic with no external input. Style or
readability concerns (use code-standards). Performance investigation
(use perf-profile).
Principles
Non-negotiable. Apply before consulting the checklist.
-
Never trust external input. All data crossing a trust boundary is
hostile until validated: HTTP bodies, query parameters, WebSocket messages,
deserialized payloads, file uploads, and DNS responses.
-
Auth is not optional. Every endpoint that serves or mutates data must
verify identity and authorization. Anonymous access is an explicit design
choice, never a default.
-
All allocations must be bounded. No unbounded Vec, String, HashMap, or
equivalent grown from user-controlled input. Set hard limits and reject
input that exceeds them.
-
Secrets never appear in logs, source, or error messages. Credentials,
tokens, API keys, and private keys are redacted in debug output, never
hardcoded, and zeroized when no longer needed.
-
Fail closed. When validation, auth, or a safety check fails, deny the
request. Do not fall through to a permissive default.
-
Defense in depth. No single layer is the only defense. Validate at the
boundary, re-validate at the data layer, and enforce at the auth layer.
Checklist
When writing code that handles external input, verify each relevant category.
Resource bounds
Input validation and sanitization
Authentication and authorization
Secret handling
Cryptography
Supply chain
Memory safety
Container and infrastructure
Error handling
Graph Integration
0. Context recall
Query prior security concerns for this project before starting:
MATCH (sc:SecurityConcern)
WHERE sc.project = $project AND sc.status = 'open'
OPTIONAL MATCH (sc)-[:affects]->(target)
RETURN sc.summary, sc.severity, sc.category, sc.cve,
labels(target) AS affected_type, target.name AS affected_name
ORDER BY sc.severity
Present open concerns to the user: "N open security concerns from prior
audits. [Summarize top items]." This establishes baseline before new analysis.
Also query dependencies flagged as security-relevant:
MATCH (d:dependency {security_relevant: true})
RETURN d.name, d.version
Session creation
Create a session at audit start per selene-integration.md.
Graph write: security concern
After each finding is triaged (fix now, defer, accept, false positive),
write a SecurityConcern node:
INSERT (sc:SecurityConcern {
project: $project,
summary: $summary,
severity: $severity,
status: $triage_status,
category: $stride_category,
found_date: date(),
cve: $cve,
audit_session: $session_id
})
RETURN id(sc) AS concern_id
Link to session, affected code, and affected dependencies per patterns
in selene-patterns.md.
Graph write: mitigation
When a fix is applied and committed:
MATCH (sc:SecurityConcern) WHERE id(sc) = $concern_id
MERGE (c:GitCommit {sha: $full_sha})
ON CREATE SET c.project = $project, c.short_sha = $short_sha,
c.message = $commit_message, c.author = $author, c.date = date(),
c.branch = $branch
INSERT (sc)-[:mitigated_by]->(c)
SET sc.status = 'mitigated'
Manual audit mode
When invoked manually, determine scope first:
For full codebase audit: delegate to the security-auditor agent
using the Agent tool. This keeps heavy scanning out of the main context.
The agent has the safety-checks methodology preloaded and uses read-only
tools.
For focused audit (specific module, endpoint, or trust boundary):
perform the analysis directly in the main conversation. Present findings
one at a time per the triage pattern below.
Setup
- If
$ARGUMENTS specifies a scope, use it to focus the audit.
For delegated audits, include the scope in the delegation prompt.
- The auditor identifies all trust boundaries (external input entry points,
auth boundaries, service-to-service calls, data persistence layers).
STRIDE analysis
For each trust boundary, evaluate:
| Threat | Question |
|---|
| Spoofing | Can users impersonate others? Are tokens validated on every request? |
| Tampering | Can request data be modified? Are inputs validated server-side? |
| Repudiation | Are security-relevant actions logged? Are logs tamper-proof? |
| Information Disclosure | Do errors leak internals? Are secrets in code/logs? Data encrypted at rest/transit? |
| Denial of Service | Unbounded queries? Missing rate limits? Algorithmic complexity attacks? |
| Elevation of Privilege | Can users access admin functions? Is authorization checked at every layer? |
Report
- Run every item in the checklist above against the codebase.
- Report findings grouped by STRIDE category with severity:
- Critical - active exploitability, data exposure, auth bypass
- High - exploitable with effort, missing auth on endpoints
- Medium - defense-in-depth gaps, missing rate limits
- Low - hardening opportunities, best practice deviations
- For each finding, include: file, line, STRIDE category, and specific fix.
- Summarize: total findings by severity, top 3 priorities, and recommended
fix order.
7. Triage findings with user
After the security-auditor returns findings, present critical and high
findings to the user one at a time before applying any fixes:
- For each Critical finding, present:
- The finding (file, line, STRIDE category, specific vulnerability)
- Your recommended fix
- Ask: fix now, defer (with risk acknowledgment), or skip
- Wait for the user's decision before presenting the next finding
- After all Critical findings, ask: "Move to High findings, or stop here?"
- Repeat for High severity. Medium and Low findings can be summarized
as a group with the user choosing to review individually or batch-fix.
Common Rationalizations
| Rationalization | Why It's Wrong |
|---|
| "Internal-only code doesn't need input validation" | Internal today, exposed tomorrow. Trust boundaries shift. Validate at every boundary. |
| "Middleware handles auth, endpoints don't need checks" | Middleware can be bypassed, misconfigured, or skipped in new routes. Defense in depth means checking at every layer. |
| "It's a prototype, security hardening comes later" | Prototypes ship. Security bolted on later is security never done right. |
| "Standard library handles crypto, skip crypto review" | The standard library provides primitives. Using them wrong (ECB mode, weak KDF, hardcoded IV) is the actual risk. |
| "Well-known packages can't be compromised" | event-stream, ua-parser-js, colors.js were all well-known. Popularity is not security. |
Red Flags
Stop and reassess if you observe:
- Skipping checklist categories because "the code looks safe"
- No STRIDE analysis performed for endpoints handling external input
- Treating popularity as proof of security for dependencies
- Reporting zero findings (even well-written code has hardening opportunities)
Verification
Supporting files
Language-specific (load ONLY the one matching the project language):
Scope-conditional (load only when the audit covers the relevant domain):
- secrets-patterns.md - Regex patterns for detecting
hardcoded secrets. Load when checking secret handling or running a full audit.
- crypto-guidelines.md - Approved and deprecated
cryptographic algorithms. Load when the codebase uses cryptographic
operations or running a full audit.
Never load all five files at once. For a typical single-language audit,
load one language file plus only the domain files relevant to the scope.