// From config/schema.ts — structural validation
export const StructuralCouplingContractSchema = z.object({
id: z.string().min(1),
mode: z.enum(['BLOCK', 'WARN']),
description: z.string(),
anchorRefs: z.array(z.string()).optional(),
triggers: z.array(TriggerSpecSchema).min(1),
maxOverrides: z.number().default(3),
})
Crosscutting Concept: Security
1. Threat Model
Assets Protected
| Asset | Description | Value |
|---|---|---|
Config file integrity |
|
High |
Session state integrity |
|
Medium |
Plugin execution integrity |
Plugin must enforce rules correctly |
High |
User’s source code |
Plugin can read tool arguments (toolName, args) |
High |
Threats
| Threat | Impact | Likelihood | Mitigation |
|---|---|---|---|
Config tampering — attacker modifies YAML to disable enforcement |
Steering bypass |
Low (local file) |
File permissions (user-owned); config hash verification (v2) |
Config injection — attacker injects YAML with malicious trigger patterns |
Denial of service |
Low |
Zod schema validation rejects unknown fields |
Memory disclosure — session state leaked via crash dump |
Override count disclosure |
Very low |
In-memory only, no persistent storage |
Dependency compromise — malicious npm package |
Full compromise |
Low |
Lock file, |
Plugin hook bypass — opencode bug allows bypassing hook |
Enforcement bypass |
Low |
Fail-open as fallback; opencode SDK issues tracked |
PII in tool arguments — user accidentally includes secrets in file paths |
Information disclosure |
Medium |
Plugin does NOT log tool arguments — only toolName |
What the plugin does NOT handle
| Security domain | Handled by | Rationale |
|---|---|---|
Authentication |
opencode itself |
Plugin does not authenticate users |
Authorization |
opencode permission system |
Plugin uses |
Network security |
User’s environment |
Plugin has zero external HTTP calls |
Secrets management |
age, 1Password, etc. |
Plugin explicitly excludes secrets |
File system permissions |
OS |
Plugin reads YAML from user-owned config directory |
Source Anchor (Quelle): Architecture Constraints (02-architecture-constraints.md): "No secrets — Plugin never handles passwords, tokens, or API keys. No integration with age or other secret stores." — Section 2, Technical Constraints.
2. Input Validation
YAML Config Validation
All configuration is validated against a Zod schema before loading:
| Validation | Method | Rejects |
|---|---|---|
Contract ID format |
|
Empty IDs |
Mode |
|
Invalid modes |
Trigger type |
|
Unknown types |
Trigger pattern |
String regex validation |
Invalid patterns |
maxOverrides |
|
Non-numeric values |
Unknown fields |
Zod |
Configurable |
Source Anchor (Quelle): Zod documentation: https://zod.dev/. Zod
.strict()rejects unknown keys;.passthrough()allows them with warnings.
Tool Input Validation
Custom tools (anchor-bypass, anchor-status, anchor-config-reload) validate their own parameters:
| Tool | Parameter | Validation |
|---|---|---|
|
|
Required, non-empty |
|
None |
— |
|
None |
Checks |
3. Logging and PII
Logging Policy
| Logged | Not logged | Rationale |
|---|---|---|
Tool name (e.g., "edit", "write") |
Tool arguments (file paths, content) |
Arguments may contain proprietary code or secrets |
Contract ID (e.g., "step-confirmation") |
User identity or agent name |
PII minimization (GDPR Art. 5(1)(c)) |
Verdict (allow/block/warn) |
IP addresses, hostnames |
Not needed for enforcement |
Override count + reason |
Full conversation history |
Reasons are user-provided, brief strings |
Timestamp (session-relative) |
Absolute timestamps or timezone |
Avoids session reconstruction |
Source Anchor (Quelle): GDPR Article 5(1)(c) — Data minimisation: "Personal data shall be adequate, relevant and limited to what is necessary in relation to the purposes for which they are processed."
Log Storage
-
Logs are in-memory only during the session
-
Not persisted to disk by the plugin
-
Lost on opencode restart
-
opencode itself may log plugin interactions — that is outside the plugin’s control
ISO 27001: Data Leakage Prevention (A.8.12)
The plugin ensures no data exfiltration by: - Zero external HTTP calls (architectural constraint) - No file writes beyond reading its own config YAML - No network connections of any kind - No telemetry — the plugin does not phone home
4. Supply Chain Security
Dependency Verification
| Measure | Status | Implementation |
|---|---|---|
Lock file |
✅ Required |
|
Integrity check |
✅ npm built-in |
|
Signature verification |
✅ npm v10+ |
|
SBOM |
🔄 Planned (v1.1) |
|
Source Anchor (Quelle): npm registry integrity: https://docs.npmjs.com/about-registry-integrity-and-signatures. "Packages in the npm registry include integrity checksums (SHA-512) and optionally package signatures."
Vulnerability Scanning Cadence
| Scan | Frequency | Tool | Action on Finding |
|---|---|---|---|
Runtime dependencies |
Weekly |
Renovate + |
Patch within SLA |
Dev dependencies |
Weekly |
Renovate + |
Automerge patch/minor |
Transitive dependencies |
Weekly |
Renovate (via |
Inherited from direct deps |
Full audit |
Pre-release |
|
Block release if high/critical |
5. Secure Development
Developer Workstation Security
| Practice | Standard |
|---|---|
2FA on GitHub |
Required for all maintainers |
Signed commits |
GPG or SSH commit signing |
No secrets in code |
|
Dependency updates |
Renovate bot, never manual |
Code Review Requirements
| Change type | Reviewer | Must include |
|---|---|---|
Bug fix |
1 maintainer |
Test case reproducing the bug |
New feature |
2 maintainers |
Tests, CHANGELOG entry, anchor documentation |
Config schema change |
2 maintainers |
Migration guide, Zod schema update |
Security fix |
2 maintainers |
GH Security Advisory reference |
Testing for Security
| Test type | Covers | Tool |
|---|---|---|
Unit tests |
Enforcement logic, edge cases |
vitest |
Input validation |
Malformed YAML, injection attempts |
vitest + Zod |
Hook error handling |
Fail-open behavior, crash recovery |
vitest with mock |
Supply chain |
Dependency vulnerabilities |
npm audit + Renovate |
6. Incident Response
Security Incident Handling
For the plugin’s own code (not for opencode or user systems):
-
Report via GitHub Security Advisory or email to security@semantic-anchors.dev
-
Triage within 48 hours — determine severity and affected versions
-
Fix developed in private fork
-
Patch released as PATCH version bump
-
Disclosure — CVE + GH Advisory published after patch is available
-
Post-mortem within 14 days
Expected-Use Security Boundaries
The plugin operates within opencode’s sandbox: - Plugin code runs in the same Node.js process as opencode - Plugin has access to: tool names, tool arguments (passed by opencode), file system (config read) - Plugin does NOT have access to: network, user credentials, other process memory - If opencode itself is compromised, the plugin cannot provide security guarantees
Boundary Anchor (Scope-Grenze): Das Plugin kann keine Sicherheitsgarantien geben, wenn opencode selbst kompromittiert ist. Es ist ein runtime steering tool, kein security enforcement layer. Die Sicherheit des Gesamtsystems hängt von der Sicherheit der opencode-Installation ab.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.