contextos-agents 2.3.1 → 2.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/adapters/cursor/export.js +3 -27
- package/.agents/adapters/gemini/export.js +5 -7
- package/.agents/adapters/shared.js +14 -1
- package/.agents/adapters/zed/export.js +4 -16
- package/.agents/compiled/registry.v2.json +33 -33
- package/.agents/compiled/registry.v2.sha256 +1 -1
- package/.agents/compiler/manifest-compiler.js +8 -5
- package/.agents/core/skills/context-manager/EXAMPLES.md +5 -17
- package/.agents/core/skills/context-manager/SKILL.md +10 -100
- package/.agents/core/skills/context-manager/TROUBLESHOOTING.md +6 -6
- package/.agents/core/skills/context-manager/VALIDATION.json +115 -4
- package/.agents/core/skills/context-manager/references/context-rules.md +3 -57
- package/.agents/core/skills/context-manager/skill.yaml +1 -3
- package/.agents/core/skills/context-os/EXAMPLES.md +25 -15
- package/.agents/core/skills/context-os/SKILL.md +12 -135
- package/.agents/core/skills/context-os/TROUBLESHOOTING.md +11 -6
- package/.agents/core/skills/context-os/VALIDATION.json +115 -4
- package/.agents/core/skills/context-os/packs.yaml +10 -59
- package/.agents/core/skills/context-os/references/context-rules.md +27 -59
- package/.agents/core/skills/context-os/references/pipeline.md +14 -119
- package/.agents/core/skills/context-os/references/project-graph.md +11 -100
- package/.agents/core/skills/context-os/rules.yaml +8 -135
- package/.agents/core/skills/engineering-workflow/EXAMPLES.md +15 -50
- package/.agents/core/skills/engineering-workflow/SKILL.md +10 -10
- package/.agents/core/skills/engineering-workflow/TROUBLESHOOTING.md +11 -19
- package/.agents/core/skills/engineering-workflow/VALIDATION.json +115 -4
- package/.agents/core/skills/engineering-workflow/references/workflow.md +55 -317
- package/.agents/core/skills/gemini-precision/EXAMPLES.md +33 -53
- package/.agents/core/skills/gemini-precision/SKILL.md +11 -147
- package/.agents/core/skills/gemini-precision/TROUBLESHOOTING.md +12 -25
- package/.agents/core/skills/gemini-precision/VALIDATION.json +115 -4
- package/.agents/core/skills/gemini-precision/skill.yaml +1 -1
- package/.agents/core/skills/gstack-roles/EXAMPLES.md +5 -21
- package/.agents/core/skills/gstack-roles/SKILL.md +10 -12
- package/.agents/core/skills/gstack-roles/TROUBLESHOOTING.md +6 -12
- package/.agents/core/skills/gstack-roles/VALIDATION.json +115 -4
- package/.agents/core/skills/gstack-roles/references/roles.md +3 -147
- package/.agents/core/skills/ponytail-mindset/EXAMPLES.md +12 -45
- package/.agents/core/skills/ponytail-mindset/SKILL.md +10 -13
- package/.agents/core/skills/ponytail-mindset/TROUBLESHOOTING.md +10 -19
- package/.agents/core/skills/ponytail-mindset/VALIDATION.json +115 -4
- package/.agents/core/skills/ponytail-mindset/references/minimalism.md +58 -174
- package/.agents/core/skills/security/EXAMPLES.md +19 -55
- package/.agents/core/skills/security/SKILL.md +61 -137
- package/.agents/core/skills/security/TROUBLESHOOTING.md +13 -19
- package/.agents/core/skills/security/VALIDATION.json +115 -4
- package/.agents/core/skills/security/skill.yaml +1 -1
- package/.agents/generated/claude/skills/context-manager/EXAMPLES.md +5 -17
- package/.agents/generated/claude/skills/context-manager/SKILL.md +9 -96
- package/.agents/generated/claude/skills/context-manager/TROUBLESHOOTING.md +6 -6
- package/.agents/generated/claude/skills/context-manager/VALIDATION.json +115 -4
- package/.agents/generated/claude/skills/context-manager/references/context-rules.md +3 -57
- package/.agents/generated/claude/skills/context-os/EXAMPLES.md +25 -15
- package/.agents/generated/claude/skills/context-os/SKILL.md +11 -133
- package/.agents/generated/claude/skills/context-os/TROUBLESHOOTING.md +11 -6
- package/.agents/generated/claude/skills/context-os/VALIDATION.json +115 -4
- package/.agents/generated/claude/skills/context-os/packs.yaml +10 -59
- package/.agents/generated/claude/skills/context-os/references/context-rules.md +27 -59
- package/.agents/generated/claude/skills/context-os/references/pipeline.md +14 -119
- package/.agents/generated/claude/skills/context-os/references/project-graph.md +11 -100
- package/.agents/generated/claude/skills/context-os/rules.yaml +8 -135
- package/.agents/generated/claude/skills/engineering-workflow/EXAMPLES.md +15 -50
- package/.agents/generated/claude/skills/engineering-workflow/SKILL.md +9 -9
- package/.agents/generated/claude/skills/engineering-workflow/TROUBLESHOOTING.md +11 -19
- package/.agents/generated/claude/skills/engineering-workflow/VALIDATION.json +115 -4
- package/.agents/generated/claude/skills/engineering-workflow/references/workflow.md +55 -317
- package/.agents/generated/claude/skills/gemini-precision/EXAMPLES.md +33 -53
- package/.agents/generated/claude/skills/gemini-precision/SKILL.md +10 -143
- package/.agents/generated/claude/skills/gemini-precision/TROUBLESHOOTING.md +12 -25
- package/.agents/generated/claude/skills/gemini-precision/VALIDATION.json +115 -4
- package/.agents/generated/claude/skills/gstack-roles/EXAMPLES.md +5 -21
- package/.agents/generated/claude/skills/gstack-roles/SKILL.md +9 -11
- package/.agents/generated/claude/skills/gstack-roles/TROUBLESHOOTING.md +6 -12
- package/.agents/generated/claude/skills/gstack-roles/VALIDATION.json +115 -4
- package/.agents/generated/claude/skills/gstack-roles/references/roles.md +3 -147
- package/.agents/generated/claude/skills/ponytail-mindset/EXAMPLES.md +12 -45
- package/.agents/generated/claude/skills/ponytail-mindset/SKILL.md +9 -12
- package/.agents/generated/claude/skills/ponytail-mindset/TROUBLESHOOTING.md +10 -19
- package/.agents/generated/claude/skills/ponytail-mindset/VALIDATION.json +115 -4
- package/.agents/generated/claude/skills/ponytail-mindset/references/minimalism.md +58 -174
- package/.agents/generated/claude/skills/security/EXAMPLES.md +19 -55
- package/.agents/generated/claude/skills/security/SKILL.md +60 -134
- package/.agents/generated/claude/skills/security/TROUBLESHOOTING.md +13 -19
- package/.agents/generated/claude/skills/security/VALIDATION.json +115 -4
- package/.agents/generated/gemini/skills/context-manager/EXAMPLES.md +5 -17
- package/.agents/generated/gemini/skills/context-manager/SKILL.md +10 -99
- package/.agents/generated/gemini/skills/context-manager/TROUBLESHOOTING.md +6 -6
- package/.agents/generated/gemini/skills/context-manager/VALIDATION.json +115 -4
- package/.agents/generated/gemini/skills/context-manager/references/context-rules.md +3 -57
- package/.agents/generated/gemini/skills/context-os/EXAMPLES.md +25 -15
- package/.agents/generated/gemini/skills/context-os/SKILL.md +12 -135
- package/.agents/generated/gemini/skills/context-os/TROUBLESHOOTING.md +11 -6
- package/.agents/generated/gemini/skills/context-os/VALIDATION.json +115 -4
- package/.agents/generated/gemini/skills/context-os/packs.yaml +10 -59
- package/.agents/generated/gemini/skills/context-os/references/context-rules.md +27 -59
- package/.agents/generated/gemini/skills/context-os/references/pipeline.md +14 -119
- package/.agents/generated/gemini/skills/context-os/references/project-graph.md +11 -100
- package/.agents/generated/gemini/skills/context-os/rules.yaml +8 -135
- package/.agents/generated/gemini/skills/engineering-workflow/EXAMPLES.md +15 -50
- package/.agents/generated/gemini/skills/engineering-workflow/SKILL.md +10 -11
- package/.agents/generated/gemini/skills/engineering-workflow/TROUBLESHOOTING.md +11 -19
- package/.agents/generated/gemini/skills/engineering-workflow/VALIDATION.json +115 -4
- package/.agents/generated/gemini/skills/engineering-workflow/references/workflow.md +55 -317
- package/.agents/generated/gemini/skills/gemini-precision/EXAMPLES.md +33 -53
- package/.agents/generated/gemini/skills/gemini-precision/SKILL.md +11 -145
- package/.agents/generated/gemini/skills/gemini-precision/TROUBLESHOOTING.md +12 -25
- package/.agents/generated/gemini/skills/gemini-precision/VALIDATION.json +115 -4
- package/.agents/generated/gemini/skills/gstack-roles/EXAMPLES.md +5 -21
- package/.agents/generated/gemini/skills/gstack-roles/SKILL.md +10 -13
- package/.agents/generated/gemini/skills/gstack-roles/TROUBLESHOOTING.md +6 -12
- package/.agents/generated/gemini/skills/gstack-roles/VALIDATION.json +115 -4
- package/.agents/generated/gemini/skills/gstack-roles/references/roles.md +3 -147
- package/.agents/generated/gemini/skills/ponytail-mindset/EXAMPLES.md +12 -45
- package/.agents/generated/gemini/skills/ponytail-mindset/SKILL.md +10 -14
- package/.agents/generated/gemini/skills/ponytail-mindset/TROUBLESHOOTING.md +10 -19
- package/.agents/generated/gemini/skills/ponytail-mindset/VALIDATION.json +115 -4
- package/.agents/generated/gemini/skills/ponytail-mindset/references/minimalism.md +58 -174
- package/.agents/generated/gemini/skills/security/EXAMPLES.md +19 -55
- package/.agents/generated/gemini/skills/security/SKILL.md +61 -136
- package/.agents/generated/gemini/skills/security/TROUBLESHOOTING.md +13 -19
- package/.agents/generated/gemini/skills/security/VALIDATION.json +115 -4
- package/.agents/resolver/canonical-resolver.js +34 -21
- package/.agents/rules/rule-catalog.js +5 -5
- package/.agents/validate.js +9 -2
- package/.agents/validation-evidence.js +89 -0
- package/README.md +132 -207
- package/catalog/skills/typescript/SKILL.md +16 -2
- package/package.json +3 -2
|
@@ -1,64 +1,28 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Security boundary examples
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Protected document mutation
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Illustrative integration sketch: authenticate through trusted middleware, check
|
|
6
|
+
the tenant role permits the action, and scope the query by document ID and trusted
|
|
7
|
+
tenant ID. Return the established denied/missing response when no accessible
|
|
8
|
+
document matches. Tenant membership alone may not permit deletion.
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export function verifyApiKey(providedKey: string, storedKey: string): boolean {
|
|
10
|
-
return providedKey === storedKey; // Vulnerable to timing analysis!
|
|
11
|
-
}
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
### Best practice: ContextOS Standard (Constant-time buffer comparison)
|
|
10
|
+
Do not report a working endpoint from a sketch with assumed ORM/middleware.
|
|
11
|
+
Verify another user's or tenant's document is inaccessible before persistence.
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
// GOOD: crypto.timingSafeEqual executes in constant time
|
|
18
|
-
import crypto from 'crypto';
|
|
13
|
+
## Executable controls
|
|
19
14
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
The original runnable HMAC and partner-fetch blocks are in [SKILL.md](SKILL.md).
|
|
16
|
+
The verifier extracts these blocks rather than manually maintained copies.
|
|
17
|
+
Checks cover signatures and URL scheme, credentials, host, port, transport, and
|
|
18
|
+
redirect policy. Egress, DNS, and replay defenses need separate integration tests.
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
20
|
+
## Source-checkout scanner
|
|
27
21
|
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
```powershell
|
|
23
|
+
node bin/index.js scan --staged --enforce --placeholders
|
|
30
24
|
```
|
|
31
25
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
### Anti-pattern: Anti-pattern (Trusting client ID without ownership check)
|
|
37
|
-
|
|
38
|
-
```typescript
|
|
39
|
-
// BAD: any authenticated user can delete any other user's document!
|
|
40
|
-
app.delete('/api/documents/:id', requireAuth, async (req, res) => {
|
|
41
|
-
await prisma.document.delete({ where: { id: req.params.id } });
|
|
42
|
-
res.status(204).end();
|
|
43
|
-
});
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Best practice: ContextOS Standard (Multi-tenant scoped authorization check)
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
// GOOD: document deletion is strictly scoped to authenticated user or org
|
|
50
|
-
app.delete('/api/documents/:id', requireAuth, async (req, res) => {
|
|
51
|
-
const deleted = await prisma.document.deleteMany({
|
|
52
|
-
where: {
|
|
53
|
-
id: req.params.id,
|
|
54
|
-
organizationId: req.user.organizationId, // Tenant isolation
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
if (deleted.count === 0) {
|
|
59
|
-
return res.status(404).json({ error: 'Document not found or access denied' });
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return res.status(204).end();
|
|
63
|
-
});
|
|
64
|
-
```
|
|
26
|
+
This checks staged secrets and placeholders. Supply --scope <file> with the
|
|
27
|
+
actual scope JSON for write boundaries. Inspect unstaged changes separately.
|
|
28
|
+
An empty index does not prove a candidate contains no unsafe code.
|
|
@@ -1,184 +1,109 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: security
|
|
3
|
-
description:
|
|
4
|
-
Protect authentication, authorization, sensitive data, untrusted input, external integrations, and agent tool execution.
|
|
3
|
+
description: "Protect authentication, authorization, sensitive data, untrusted input, external integrations, and agent tool execution."
|
|
5
4
|
---
|
|
6
5
|
# security
|
|
7
6
|
|
|
8
7
|
## Overview
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
Protect application and agent trust boundaries. These instructions guide work;
|
|
10
|
+
automated checkers enforce only their explicitly tested scope.
|
|
11
11
|
|
|
12
12
|
## When to Use
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Authentication, authorization, protected data, inputs, cryptography, external
|
|
15
|
+
requests, payments, destructive actions, and tool execution.
|
|
15
16
|
|
|
16
17
|
## Rules & Patterns
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
#### 2. Broken Object Level Authorization (BOLA / IDOR)
|
|
38
|
-
|
|
39
|
-
- Validate user ownership on EVERY database read, update, or delete:
|
|
40
|
-
|
|
41
|
-
```typescript
|
|
42
|
-
// [GOOD] Scoped to authenticated user
|
|
43
|
-
const doc = await db.document.findFirst({
|
|
44
|
-
where: { id: documentId, tenantId: session.tenantId }
|
|
45
|
-
});
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
#### 3. Broken Authentication & Session Management
|
|
49
|
-
|
|
50
|
-
- Use Argon2id or bcrypt (cost factor ≥ 12) for password hashing.
|
|
51
|
-
- Short-lived access tokens (15 min) + secure HTTP-only refresh tokens.
|
|
52
|
-
- Enforce rate limiting and brute-force lockouts on auth endpoints.
|
|
53
|
-
|
|
54
|
-
#### 4. SSRF (Server-Side Request Forgery)
|
|
55
|
-
|
|
56
|
-
- Restrict server-side URL fetching: validate URL scheme (`https:` only), resolve IP, and block private CIDR blocks (`10.0.0.0/8`, `127.0.0.0/8`, `169.254.0.0/16`, `192.168.0.0/16`).
|
|
57
|
-
|
|
58
|
-
#### 5. Security Misconfiguration & Headers
|
|
59
|
-
|
|
60
|
-
Enforce modern production security headers:
|
|
61
|
-
|
|
62
|
-
```http
|
|
63
|
-
Content-Security-Policy: default-src 'self'
|
|
64
|
-
X-Content-Type-Options: nosniff
|
|
65
|
-
X-Frame-Options: DENY
|
|
66
|
-
Strict-Transport-Security: max-age=31536000; includeSubDomains
|
|
67
|
-
Referrer-Policy: strict-origin-when-cross-origin
|
|
68
|
-
Permissions-Policy: camera=(), microphone=(), geolocation=()
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
### AI Agent & LLM Security Invariants
|
|
74
|
-
|
|
75
|
-
When building AI workflows, tools, or MCP servers:
|
|
76
|
-
|
|
77
|
-
1. **Prompt Injection Defense**:
|
|
78
|
-
- Clearly delineate untrusted user/web content using boundary markers (e.g. `<untrusted_content>` tags).
|
|
79
|
-
- Never allow untrusted content to override system instructions or tool execution permissions.
|
|
80
|
-
2. **Tool Execution Boundaries**:
|
|
81
|
-
- Destructive operations (database drops, file deletions, payment triggers) MUST require explicit user confirmation.
|
|
82
|
-
- Restrict file system tools to the workspace root - block directory traversal (`../`).
|
|
83
|
-
3. **Secret Masking & Output Sanitization**:
|
|
84
|
-
- Scrub API keys (`sk-...`, `Bearer ...`), tokens, and credentials before writing to agent logs or step summaries.
|
|
85
|
-
4. **Sandbox Execution & Write Isolation (Supply-Chain Defense)**:
|
|
86
|
-
- Target code is inspected strictly read-only; never execute target-controlled builds or tests with write access to the repository root.
|
|
87
|
-
- Restrict process write boundaries strictly to an isolated temporary `scratch/` directory.
|
|
88
|
-
- Enforce zero outbound external network access during security audits to prevent secret exfiltration via malicious scripts or dependencies.
|
|
89
|
-
- Promote verified non-secret results to retained `artifacts/` only via trusted parent-side inspection code.
|
|
90
|
-
|
|
91
|
-
---
|
|
19
|
+
- Obtain identity from trusted authentication. Enforce ownership/tenant policy
|
|
20
|
+
before protected reads or mutations; client IDs are not authorization.
|
|
21
|
+
- Validate boundary inputs and reject unknown privilege fields. Parameterize
|
|
22
|
+
queries and encode output for its context; avoid shell interpolation. An ORM
|
|
23
|
+
does not secure interpolated raw SQL.
|
|
24
|
+
- Keep credentials out of source, logs, arguments, and client bundles. Use
|
|
25
|
+
established password/session libraries and cookie, CSRF, origin, and TLS
|
|
26
|
+
policies appropriate to the threat model.
|
|
27
|
+
- Use constant-time primitives for secret comparisons. Surrounding code and
|
|
28
|
+
length handling matter; the whole flow is not necessarily constant-time.
|
|
29
|
+
- External content remains untrusted data. Delimit it and preserve instruction
|
|
30
|
+
and tool authority; markers alone do not prevent prompt injection.
|
|
31
|
+
- Existing authorization carries forward. For destructive actions verify it
|
|
32
|
+
covers the actual target and effect; ask only for missing authority.
|
|
33
|
+
- For untrusted repositories/dependency scripts, inspect before execution,
|
|
34
|
+
isolate writes, withhold credentials, and restrict network access. Ordinary
|
|
35
|
+
authorized development uses relevant project checks. State actual sandbox
|
|
36
|
+
capabilities instead of claiming isolation the tools do not provide.
|
|
92
37
|
|
|
93
38
|
## Code Examples
|
|
94
39
|
|
|
40
|
+
### Timing-safe webhook signature comparison
|
|
95
41
|
|
|
96
|
-
|
|
42
|
+
This runnable block verifies SHA-256 hexadecimal HMAC signatures. Timestamp,
|
|
43
|
+
replay protection, raw-body capture, and provider formats are separate requirements.
|
|
97
44
|
|
|
45
|
+
<!-- example: security-hmac -->
|
|
98
46
|
```javascript
|
|
99
47
|
import crypto from 'node:crypto';
|
|
100
48
|
|
|
101
49
|
export function verifyWebhookSignature(payload, signature, secret) {
|
|
102
|
-
|
|
103
|
-
const digest =
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
if (digest.length !== sigBuffer.length) return false;
|
|
107
|
-
return crypto.timingSafeEqual(digest, sigBuffer);
|
|
50
|
+
if (typeof signature !== 'string' || !/^[a-f0-9]{64}$/i.test(signature)) return false;
|
|
51
|
+
const digest = crypto.createHmac('sha256', secret).update(payload).digest();
|
|
52
|
+
const received = Buffer.from(signature, 'hex');
|
|
53
|
+
return digest.length === received.length && crypto.timingSafeEqual(digest, received);
|
|
108
54
|
}
|
|
109
55
|
```
|
|
110
56
|
|
|
111
|
-
###
|
|
112
|
-
|
|
113
|
-
Per [OWASP SSRF Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html), naive application-level DNS pre-checks followed by standard `fetch(url)` are fundamentally flawed due to DNS rebinding (TOCTOU) and unvalidated HTTP 3xx redirects.
|
|
57
|
+
### Restricted partner URL fetch
|
|
114
58
|
|
|
115
|
-
|
|
59
|
+
Follow the [OWASP SSRF guidance](https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html).
|
|
60
|
+
A hostname check followed by ordinary DNS resolution is not a complete SSRF
|
|
61
|
+
boundary. Use a trusted egress transport/proxy that validates IPv4/IPv6 addresses
|
|
62
|
+
at connection time and blocks private, loopback, link-local, and metadata targets,
|
|
63
|
+
including DNS changes. Arbitrary URL fetchers need a separate network policy;
|
|
64
|
+
this sample covers known partner hostnames.
|
|
116
65
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
66
|
+
Supply that trusted transport explicitly. This block checks URL syntax, HTTPS,
|
|
67
|
+
credentials, port 443, a trusted hostname allowlist, and redirect policy. There
|
|
68
|
+
is no ambient fetch fallback. Local tests inject a controlled transport; they
|
|
69
|
+
do not verify production egress or DNS behavior.
|
|
121
70
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
* Enforces HTTPS, strict destination allowlist, and rejects HTTP redirects.
|
|
126
|
-
*/
|
|
127
|
-
export async function fetchFromAllowlist(
|
|
128
|
-
urlString: string,
|
|
129
|
-
allowedHostnames: ReadonlySet<string>,
|
|
130
|
-
options: RequestInit = {}
|
|
131
|
-
): Promise<Response> {
|
|
71
|
+
<!-- example: security-ssrf -->
|
|
72
|
+
```javascript
|
|
73
|
+
export async function fetchFromAllowlist(urlString, allowedHostnames, options, transport) {
|
|
132
74
|
const parsed = new URL(urlString);
|
|
133
|
-
|
|
134
|
-
// 1. Enforce HTTPS only
|
|
135
75
|
if (parsed.protocol !== 'https:') {
|
|
136
|
-
throw new Error(
|
|
76
|
+
throw new Error('SSRF blocked: protocol "' + parsed.protocol + '" is not permitted; HTTPS required');
|
|
137
77
|
}
|
|
138
|
-
|
|
139
|
-
// 2. Reject credentials in URL
|
|
140
78
|
if (parsed.username || parsed.password) {
|
|
141
79
|
throw new Error('SSRF blocked: URL credentials (user:password@host) are prohibited');
|
|
142
80
|
}
|
|
143
|
-
|
|
144
|
-
// 3. Strict positive destination allowlist (prevents internal network probing)
|
|
81
|
+
if (parsed.port && parsed.port !== '443') throw new Error('SSRF blocked: non-standard port');
|
|
145
82
|
const normalizedHost = parsed.hostname.toLowerCase();
|
|
146
83
|
if (!allowedHostnames.has(normalizedHost)) {
|
|
147
|
-
throw new Error(
|
|
84
|
+
throw new Error('SSRF blocked: destination host "' + normalizedHost + '" is not in the approved allowlist');
|
|
148
85
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
return fetch(urlString, {
|
|
152
|
-
...options,
|
|
153
|
-
redirect: 'error'
|
|
154
|
-
});
|
|
86
|
+
if (typeof transport !== 'function') throw new TypeError('Trusted egress transport required');
|
|
87
|
+
return transport(parsed.href, { ...options, redirect: 'error' });
|
|
155
88
|
}
|
|
156
89
|
```
|
|
157
90
|
|
|
158
|
-
---
|
|
159
|
-
|
|
160
91
|
## Validation Checklist
|
|
161
92
|
|
|
162
|
-
- [ ]
|
|
163
|
-
- [ ]
|
|
164
|
-
- [ ]
|
|
165
|
-
- [ ]
|
|
166
|
-
- [ ]
|
|
167
|
-
- [ ] No secrets or tokens checked into source control or exposed in logs.
|
|
168
|
-
|
|
169
|
-
---
|
|
93
|
+
- [ ] Allowed and denied identity/tenant cases are checked before data access.
|
|
94
|
+
- [ ] Invalid and unknown inputs never reach protected persistence.
|
|
95
|
+
- [ ] Secrets and production errors preserve their boundaries.
|
|
96
|
+
- [ ] External requests and tool policies are checked at the stated scope.
|
|
97
|
+
- [ ] Commands, results, unrun checks, and limitations are reported.
|
|
170
98
|
|
|
171
99
|
## Common Mistakes
|
|
172
100
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
- **Unvalidated redirects / URLs**: Allowing arbitrary URLs in redirect or fetch parameters.
|
|
177
|
-
|
|
178
|
-
---
|
|
101
|
+
Treating an allowlist as network isolation; comparing role labels instead of
|
|
102
|
+
permissions; passing client payloads into persistence; interpreting a secret scan
|
|
103
|
+
or document validator as a complete application security audit.
|
|
179
104
|
|
|
180
105
|
## Integration Notes
|
|
181
106
|
|
|
182
|
-
-
|
|
183
|
-
|
|
184
|
-
|
|
107
|
+
Use engineering-workflow's proportional verification and existing authority.
|
|
108
|
+
The staged scanner needs --placeholders for stubs and --scope with a real scope
|
|
109
|
+
JSON file for write boundaries. Validate does not replace either check.
|
|
@@ -1,19 +1,13 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
-
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
## 3. Storing Sensitive Secrets in Git or Client Bundles
|
|
16
|
-
|
|
17
|
-
- **Symptom**: API keys or JWT signing secrets exposed publicly.
|
|
18
|
-
- **Root Cause**: Hardcoding secrets in source files or prefixing server secrets with NEXT_PUBLIC_.
|
|
19
|
-
- **Fix**: Store all secrets in server-only environment variables; add git-secrets to pre-commit hooks.
|
|
1
|
+
# Security troubleshooting
|
|
2
|
+
|
|
3
|
+
- IDOR/BOLA: verify denied users/tenants before persistence and require the action
|
|
4
|
+
permission, not merely an object ID.
|
|
5
|
+
- SQL/shell interpolation: use parameters or safe argument APIs. Schema checks
|
|
6
|
+
alone do not repair command interpolation.
|
|
7
|
+
- SSRF: DNS prechecks followed by ambient fetch can resolve again; verify the
|
|
8
|
+
connection-time transport policy, A/AAAA results, and redirects.
|
|
9
|
+
- Untrusted scripts: inspect/isolate without credentials; state actual controls.
|
|
10
|
+
- Authority: confirm targets/effects against existing permission instead of
|
|
11
|
+
asking again merely because a phase changed.
|
|
12
|
+
- Green scan: inspect enabled flags, staged files, scope input, and exclusions.
|
|
13
|
+
Results do not prove all security invariants or unstaged code.
|
|
@@ -1,12 +1,123 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"x-contextos-evidence-contract": 1,
|
|
4
|
+
"title": "Scoped verification evidence",
|
|
5
|
+
"description": "Report shape and outcome consistency only; command execution and agent behavior require separate evidence.",
|
|
3
6
|
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": [
|
|
9
|
+
"status",
|
|
10
|
+
"checks",
|
|
11
|
+
"limitations"
|
|
12
|
+
],
|
|
4
13
|
"properties": {
|
|
5
|
-
"
|
|
6
|
-
"
|
|
14
|
+
"status": {
|
|
15
|
+
"enum": [
|
|
16
|
+
"verified",
|
|
17
|
+
"partial",
|
|
18
|
+
"not_run"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"checks": {
|
|
22
|
+
"type": "array",
|
|
23
|
+
"items": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"additionalProperties": false,
|
|
26
|
+
"required": [
|
|
27
|
+
"command",
|
|
28
|
+
"exitCode",
|
|
29
|
+
"scope"
|
|
30
|
+
],
|
|
31
|
+
"properties": {
|
|
32
|
+
"command": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"minLength": 1
|
|
35
|
+
},
|
|
36
|
+
"exitCode": {
|
|
37
|
+
"type": [
|
|
38
|
+
"integer",
|
|
39
|
+
"null"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"scope": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"minLength": 1
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"limitations": {
|
|
50
|
+
"type": "array",
|
|
51
|
+
"items": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"minLength": 1
|
|
54
|
+
}
|
|
7
55
|
}
|
|
8
56
|
},
|
|
9
|
-
"
|
|
10
|
-
|
|
57
|
+
"allOf": [
|
|
58
|
+
{
|
|
59
|
+
"if": {
|
|
60
|
+
"properties": {
|
|
61
|
+
"status": {
|
|
62
|
+
"const": "verified"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"then": {
|
|
67
|
+
"properties": {
|
|
68
|
+
"checks": {
|
|
69
|
+
"minItems": 1,
|
|
70
|
+
"items": {
|
|
71
|
+
"properties": {
|
|
72
|
+
"exitCode": {
|
|
73
|
+
"const": 0
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"if": {
|
|
83
|
+
"properties": {
|
|
84
|
+
"status": {
|
|
85
|
+
"enum": [
|
|
86
|
+
"partial",
|
|
87
|
+
"not_run"
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"then": {
|
|
93
|
+
"properties": {
|
|
94
|
+
"limitations": {
|
|
95
|
+
"minItems": 1
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"if": {
|
|
102
|
+
"properties": {
|
|
103
|
+
"status": {
|
|
104
|
+
"const": "not_run"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"then": {
|
|
109
|
+
"properties": {
|
|
110
|
+
"checks": {
|
|
111
|
+
"items": {
|
|
112
|
+
"properties": {
|
|
113
|
+
"exitCode": {
|
|
114
|
+
"type": "null"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
11
122
|
]
|
|
12
123
|
}
|
|
@@ -59,10 +59,10 @@ const WORKFLOW_TEMPLATES = {
|
|
|
59
59
|
summary: 'High-risk feature: auth, migration, public API, security, CI, concurrency',
|
|
60
60
|
steps: [
|
|
61
61
|
'1. SPEC: Document explicit in-scope/out-of-scope and acceptance criteria',
|
|
62
|
-
'2.
|
|
62
|
+
'2. PLAN: Scoped tasks, risk mitigation, and rollback strategy; carry existing authorization forward',
|
|
63
63
|
'3. ISOLATED_CHANGE: Surgical implementation strictly within planned files',
|
|
64
|
-
'4.
|
|
65
|
-
'5.
|
|
64
|
+
'4. VERIFICATION: Behavioral regression checks and relevant integration, security, and project gates',
|
|
65
|
+
'5. REVIEW: Inspect correctness and applicable security, database, or accessibility boundaries; distinguish self-review from peer review',
|
|
66
66
|
],
|
|
67
67
|
},
|
|
68
68
|
destructive: {
|
|
@@ -71,7 +71,7 @@ const WORKFLOW_TEMPLATES = {
|
|
|
71
71
|
steps: [
|
|
72
72
|
'1. EXPLICIT_AUTHORITY: Confirm explicit user authorization and bounds',
|
|
73
73
|
'2. ROLLBACK_REHEARSAL: Verify snapshot, backup, or rollback transaction log',
|
|
74
|
-
'3. GUARDED_CHANGE:
|
|
74
|
+
'3. GUARDED_CHANGE: Use supported transactional project tools or a verified backup and bounded operation',
|
|
75
75
|
'4. POST_VERIFY: Confirm integrity, state consistency, and absence of data loss',
|
|
76
76
|
],
|
|
77
77
|
},
|
|
@@ -391,24 +391,38 @@ function collectWorkspaceEvidence(projectRoot, registry) {
|
|
|
391
391
|
/**
|
|
392
392
|
* Evaluates task risk level according to Milestone 3 spec.
|
|
393
393
|
*/
|
|
394
|
+
// JavaScript \\b/\\w do not delimit Cyrillic words. Use Unicode boundaries for
|
|
395
|
+
// task phrases, including stem suffixes where the language requires them.
|
|
396
|
+
function matchesTaskPhrase(text, pattern) {
|
|
397
|
+
return new RegExp(`(?:^|[^\\p{L}\\p{N}_])(?:${pattern})(?=$|[^\\p{L}\\p{N}_])`, 'iu').test(text);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const SECURITY_TASK_PATTERN = String.raw`secur\w*|auth\w*|jwt|passwords?|tokens?|secrets?|permissions?|idor|bola|ssrf|csrf|xss|login|access\s*control|rate\s*limit|безопасн[\p{L}]*|авториз[\p{L}]*|аутентифик[\p{L}]*|парол[\p{L}]*|токен[\p{L}]*|доступ(?:а|у|ом|е|ы|ов)?|прав[\p{L}]*\s+доступ[\p{L}]*`;
|
|
401
|
+
|
|
402
|
+
// Bounded noun phrases allow common articles/adjectives without interpreting
|
|
403
|
+
// "remove unused imports from files" as deletion of the files themselves.
|
|
404
|
+
const DESTRUCTIVE_TASK_PATTERN = [
|
|
405
|
+
String.raw`(?:delete|remove|erase|purge|drop)\s+(?:(?:all|the|a|an|these|those|selected|old|stale|temporary|generated|unused|existing)\s+){0,4}(?:files?|folders?|directory|directories|tables?|databases?|rows?|records?)`,
|
|
406
|
+
String.raw`(?:удал[\p{L}]*|сотри|стереть|стирай|очист[\p{L}]*|уничтож[\p{L}]*)\s+(?:(?:все|всю|весь|всех|эти|эту|этот|стар[\p{L}]*|временн[\p{L}]*|выбранн[\p{L}]*|неиспользуем[\p{L}]*|сгенерированн[\p{L}]*)\s+){0,4}(?:баз[\p{L}]*|таблиц[\p{L}]*|диск[\p{L}]*|файл[\p{L}]*|папк[\p{L}]*)`,
|
|
407
|
+
String.raw`rm\s+-(?:rf|fr)|truncate|destroy|delete\s*from|format\s*disk|git\s+reset\s+--hard|git\s+push\s+(?:--force|-f)|git\s+clean\s+-[a-z]*f[a-z]*`,
|
|
408
|
+
].join('|');
|
|
409
|
+
|
|
394
410
|
function evaluateRisk(taskText, files = []) {
|
|
395
411
|
const reasons = [];
|
|
396
412
|
const text = (taskText || '').toLowerCase();
|
|
397
413
|
let value = 'standard';
|
|
398
414
|
|
|
399
415
|
// Destructive operations
|
|
400
|
-
if (
|
|
401
|
-
/\b(удали\w*\s*(?:базу|таблиц|диск|файл)|очист\w*\s*базу|уничтож\w*)\b/i.test(text)) {
|
|
416
|
+
if (matchesTaskPhrase(text, DESTRUCTIVE_TASK_PATTERN)) {
|
|
402
417
|
reasons.push({ kind: 'risk_keyword', weight: 100, reason: 'Mentions destructive database or filesystem operation' });
|
|
403
418
|
value = 'destructive';
|
|
404
|
-
} else if (
|
|
405
|
-
|
|
406
|
-
files.some(f =>
|
|
419
|
+
} else if (matchesTaskPhrase(text, SECURITY_TASK_PATTERN) ||
|
|
420
|
+
matchesTaskPhrase(text, String.raw`migration|schema|billing|payments?|credit\s*card|crypto|concurr\w*|public\s*api|ci|миграц[\p{L}]*|плат[её]ж[\p{L}]*|конкурент[\p{L}]*|параллельн[\p{L}]*|публичн[\p{L}]*\s*api`) ||
|
|
421
|
+
files.some(f => /(?:auth|security|migrations?|schema|\.github\/workflows)(?:[^a-z]|$)/i.test(f))) {
|
|
407
422
|
// High-risk operations
|
|
408
423
|
reasons.push({ kind: 'risk_keyword', weight: 50, reason: 'Touches security, authentication, migration, or sensitive domain' });
|
|
409
424
|
value = 'high';
|
|
410
|
-
} else if ((
|
|
411
|
-
/\b(опечатк\w*|документац\w*|комментар\w*|форматирован\w*)\b/i.test(text)) &&
|
|
425
|
+
} else if (matchesTaskPhrase(text, String.raw`typo|readme|docs?|comments?|format|lint|prettier|опечатк[\p{L}]*|документац[\p{L}]*|комментар[\p{L}]*|форматирован[\p{L}]*`) &&
|
|
412
426
|
files.every(f => /\.(md|txt|json|ya?ml)$/i.test(f))) {
|
|
413
427
|
// Routine operations
|
|
414
428
|
reasons.push({ kind: 'risk_keyword', weight: 10, reason: 'Routine documentation or formatting change' });
|
|
@@ -437,19 +451,19 @@ function resolvePhaseAndRole(phaseArg, taskText, selectedSkills) {
|
|
|
437
451
|
phaseSource = 'explicit';
|
|
438
452
|
} else {
|
|
439
453
|
const lower = (taskText || '').toLowerCase();
|
|
440
|
-
if (
|
|
454
|
+
if (matchesTaskPhrase(lower, String.raw`spec|requirements|user\s*story|критери[\p{L}]*|требован[\p{L}]*`)) {
|
|
441
455
|
phaseValue = 'Define';
|
|
442
456
|
phaseSource = 'prompt';
|
|
443
|
-
} else if (
|
|
457
|
+
} else if (matchesTaskPhrase(lower, String.raw`plan|architecture|design\s*the\s*system|спланир[\p{L}]*|архитектур[\p{L}]*`)) {
|
|
444
458
|
phaseValue = 'Plan';
|
|
445
459
|
phaseSource = 'prompt';
|
|
446
|
-
} else if (
|
|
460
|
+
} else if (matchesTaskPhrase(lower, String.raw`review|audit|check\s*pr|ревью|провер[\p{L}]*\s*код[\p{L}]*`)) {
|
|
447
461
|
phaseValue = 'Review';
|
|
448
462
|
phaseSource = 'prompt';
|
|
449
|
-
} else if (
|
|
463
|
+
} else if (matchesTaskPhrase(lower, String.raw`tests?|vitest|jest|playwright|tdd|тест[\p{L}]*`)) {
|
|
450
464
|
phaseValue = 'Verify';
|
|
451
465
|
phaseSource = 'prompt';
|
|
452
|
-
} else if (
|
|
466
|
+
} else if (matchesTaskPhrase(lower, String.raw`deploy|release|ship|production|релиз[\p{L}]*|деплой[\p{L}]*`)) {
|
|
453
467
|
phaseValue = 'Ship';
|
|
454
468
|
phaseSource = 'prompt';
|
|
455
469
|
}
|
|
@@ -747,8 +761,7 @@ class CanonicalResolver {
|
|
|
747
761
|
// Exact alias match
|
|
748
762
|
for (const alias of signals.aliases || []) {
|
|
749
763
|
const escaped = alias.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
750
|
-
|
|
751
|
-
if (re.test(taskLower)) {
|
|
764
|
+
if (matchesTaskPhrase(taskLower, escaped)) {
|
|
752
765
|
addEvidence(id, 'alias', WEIGHTS.EXACT_ALIAS, `Exact alias match "${alias}" in task description`);
|
|
753
766
|
break;
|
|
754
767
|
}
|
|
@@ -757,8 +770,8 @@ class CanonicalResolver {
|
|
|
757
770
|
// Keyword matches
|
|
758
771
|
for (const kw of signals.keywords || []) {
|
|
759
772
|
const escaped = kw.value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
760
|
-
const
|
|
761
|
-
if (
|
|
773
|
+
const pattern = kw.locale === 'ru' ? `${escaped}[\\p{L}]*` : escaped;
|
|
774
|
+
if (matchesTaskPhrase(taskLower, pattern)) {
|
|
762
775
|
const w = kw.weight || WEIGHTS.TASK_KEYWORD_STRONG;
|
|
763
776
|
addEvidence(id, 'keyword', w, `Task keyword "${kw.value}" (+${w})`);
|
|
764
777
|
}
|
|
@@ -788,7 +801,7 @@ class CanonicalResolver {
|
|
|
788
801
|
{ id: 'react', re: /\b(react|reactjs|useOptimistic)\b|компонент|хук|модал\w*/i, w: 40, kw: 'react' },
|
|
789
802
|
{ id: 'typescript', re: /\b(typescript|type-?safe|generics?|tsconfig)\b|тайпскрипт|типизац/i, w: 40, kw: 'typescript' },
|
|
790
803
|
{ id: 'ui-ux-pro', re: /\b(ui|ux|tailwind|styling)\b|дизайн|верстк|макет|интерфейс|модал\w*/i, w: 35, kw: 'ui/ux' },
|
|
791
|
-
{ id: 'security', re:
|
|
804
|
+
{ id: 'security', re: { test: text => matchesTaskPhrase(text, SECURITY_TASK_PATTERN) }, w: 40, kw: 'security' },
|
|
792
805
|
{ id: 'database', re: /\b(database|sql|postgres|prisma|drizzle|migration|orm)\b|баз.*данн|миграц|таблиц/i, w: 40, kw: 'database' },
|
|
793
806
|
{ id: 'testing', re: /\b(vitest|jest|playwright|tdd|bdd|e2e)\b|тестирован|покрыти|юнит|тест/i, w: 40, kw: 'testing' },
|
|
794
807
|
{ id: 'performance', re: /\b(performance|latency|lcp|cls|inp|core\s*web\s*vitals)\b|производительн|ускор|быстр|throughput/i, w: 40, kw: 'performance' },
|