@sponsio/sdk 0.1.0-alpha.3

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.
Files changed (113) hide show
  1. package/contracts/capability/credentials.yaml +188 -0
  2. package/contracts/capability/database.yaml +141 -0
  3. package/contracts/capability/filesystem-strict.yaml +101 -0
  4. package/contracts/capability/filesystem.yaml +239 -0
  5. package/contracts/capability/self-modify.yaml +152 -0
  6. package/contracts/capability/shell.yaml +246 -0
  7. package/contracts/capability/subagent.yaml +184 -0
  8. package/contracts/core/llm_safety.yaml +130 -0
  9. package/contracts/core/runaway.yaml +43 -0
  10. package/contracts/core/universal.yaml +34 -0
  11. package/contracts/incident/claude-code-secret-bypass.yaml +197 -0
  12. package/contracts/incident/cursor-railway-wipe.yaml +164 -0
  13. package/contracts/incident/mcp-composition.yaml +418 -0
  14. package/contracts/incident/openclaw.yaml +500 -0
  15. package/contracts/incident/subagent-escape.yaml +177 -0
  16. package/contracts/premium/.gitkeep +7 -0
  17. package/dist/contract.d.ts +59 -0
  18. package/dist/contract.d.ts.map +1 -0
  19. package/dist/contract.js +97 -0
  20. package/dist/contract.js.map +1 -0
  21. package/dist/core/config-loader.d.ts +90 -0
  22. package/dist/core/config-loader.d.ts.map +1 -0
  23. package/dist/core/config-loader.js +530 -0
  24. package/dist/core/config-loader.js.map +1 -0
  25. package/dist/core/evaluator.d.ts +15 -0
  26. package/dist/core/evaluator.d.ts.map +1 -0
  27. package/dist/core/evaluator.js +87 -0
  28. package/dist/core/evaluator.js.map +1 -0
  29. package/dist/core/formula.d.ts +103 -0
  30. package/dist/core/formula.d.ts.map +1 -0
  31. package/dist/core/formula.js +167 -0
  32. package/dist/core/formula.js.map +1 -0
  33. package/dist/core/grounding.d.ts +43 -0
  34. package/dist/core/grounding.d.ts.map +1 -0
  35. package/dist/core/grounding.js +269 -0
  36. package/dist/core/grounding.js.map +1 -0
  37. package/dist/core/nl-parser.d.ts +12 -0
  38. package/dist/core/nl-parser.d.ts.map +1 -0
  39. package/dist/core/nl-parser.js +152 -0
  40. package/dist/core/nl-parser.js.map +1 -0
  41. package/dist/core/pack-loader.d.ts +15 -0
  42. package/dist/core/pack-loader.d.ts.map +1 -0
  43. package/dist/core/pack-loader.js +220 -0
  44. package/dist/core/pack-loader.js.map +1 -0
  45. package/dist/core/parser.d.ts +19 -0
  46. package/dist/core/parser.d.ts.map +1 -0
  47. package/dist/core/parser.js +235 -0
  48. package/dist/core/parser.js.map +1 -0
  49. package/dist/core/pattern-factory.d.ts +38 -0
  50. package/dist/core/pattern-factory.d.ts.map +1 -0
  51. package/dist/core/pattern-factory.js +222 -0
  52. package/dist/core/pattern-factory.js.map +1 -0
  53. package/dist/core/patterns.d.ts +67 -0
  54. package/dist/core/patterns.d.ts.map +1 -0
  55. package/dist/core/patterns.js +585 -0
  56. package/dist/core/patterns.js.map +1 -0
  57. package/dist/core/session-log.d.ts +91 -0
  58. package/dist/core/session-log.d.ts.map +1 -0
  59. package/dist/core/session-log.js +196 -0
  60. package/dist/core/session-log.js.map +1 -0
  61. package/dist/core/spans.d.ts +92 -0
  62. package/dist/core/spans.d.ts.map +1 -0
  63. package/dist/core/spans.js +148 -0
  64. package/dist/core/spans.js.map +1 -0
  65. package/dist/core/sto.d.ts +120 -0
  66. package/dist/core/sto.d.ts.map +1 -0
  67. package/dist/core/sto.js +147 -0
  68. package/dist/core/sto.js.map +1 -0
  69. package/dist/index.d.ts +267 -0
  70. package/dist/index.d.ts.map +1 -0
  71. package/dist/index.js +540 -0
  72. package/dist/index.js.map +1 -0
  73. package/dist/integrations/claude-agent.d.ts +29 -0
  74. package/dist/integrations/claude-agent.d.ts.map +1 -0
  75. package/dist/integrations/claude-agent.js +40 -0
  76. package/dist/integrations/claude-agent.js.map +1 -0
  77. package/dist/integrations/google-adk.d.ts +27 -0
  78. package/dist/integrations/google-adk.d.ts.map +1 -0
  79. package/dist/integrations/google-adk.js +81 -0
  80. package/dist/integrations/google-adk.js.map +1 -0
  81. package/dist/integrations/langchain.d.ts +26 -0
  82. package/dist/integrations/langchain.d.ts.map +1 -0
  83. package/dist/integrations/langchain.js +74 -0
  84. package/dist/integrations/langchain.js.map +1 -0
  85. package/dist/integrations/openai-agents.d.ts +45 -0
  86. package/dist/integrations/openai-agents.d.ts.map +1 -0
  87. package/dist/integrations/openai-agents.js +81 -0
  88. package/dist/integrations/openai-agents.js.map +1 -0
  89. package/dist/integrations/openai.d.ts +24 -0
  90. package/dist/integrations/openai.d.ts.map +1 -0
  91. package/dist/integrations/openai.js +77 -0
  92. package/dist/integrations/openai.js.map +1 -0
  93. package/dist/integrations/vercel-ai.d.ts +38 -0
  94. package/dist/integrations/vercel-ai.d.ts.map +1 -0
  95. package/dist/integrations/vercel-ai.js +107 -0
  96. package/dist/integrations/vercel-ai.js.map +1 -0
  97. package/dist/render/components.d.ts +23 -0
  98. package/dist/render/components.d.ts.map +1 -0
  99. package/dist/render/components.js +133 -0
  100. package/dist/render/components.js.map +1 -0
  101. package/dist/render/derive.d.ts +23 -0
  102. package/dist/render/derive.d.ts.map +1 -0
  103. package/dist/render/derive.js +92 -0
  104. package/dist/render/derive.js.map +1 -0
  105. package/dist/render/session-view.d.ts +19 -0
  106. package/dist/render/session-view.d.ts.map +1 -0
  107. package/dist/render/session-view.js +236 -0
  108. package/dist/render/session-view.js.map +1 -0
  109. package/dist/render/tokens.d.ts +44 -0
  110. package/dist/render/tokens.d.ts.map +1 -0
  111. package/dist/render/tokens.js +72 -0
  112. package/dist/render/tokens.js.map +1 -0
  113. package/package.json +83 -0
@@ -0,0 +1,188 @@
1
+ # =============================================================================
2
+ # sponsio/contracts/capability/credentials.yaml
3
+ #
4
+ # Capability pack — credential-shaped strings in file-write content.
5
+ # Include when your agent exposes write / edit tools and you don't
6
+ # want secrets to leak from the agent's working memory into committed
7
+ # files, READMEs, or anywhere else that gets diff'd / pushed / shared.
8
+ #
9
+ # Real-world incidents this pack defends against:
10
+ #
11
+ # - Cursor + ``.cursorignore`` bypass (Apr 2024 → Dec 2025): agent
12
+ # read ``.env`` (allowed by user) then included its content in
13
+ # prompts that were silently sent to AI providers. Same pattern
14
+ # surfaces when a sub-agent is told "summarize the project setup"
15
+ # and writes the env values verbatim into a README.
16
+ # - Claude Code sub-agent leak pattern (recurring r/ClaudeAI):
17
+ # parent agent reads ``.env`` for setup verification, spawns a
18
+ # ``Task`` sub-agent with full context, sub-agent dutifully echoes
19
+ # ``STRIPE_SECRET_KEY=...`` into a generated file. Then a final
20
+ # ``git commit && git push`` pushes secrets to a public repo.
21
+ # - Generic agent-in-IDE foot-guns: API keys ending up in commit
22
+ # messages, log lines, Slack messages composed by an agent.
23
+ #
24
+ # Threat model boundary: this pack catches credential SHAPES in tool
25
+ # *arguments* — i.e. the content the agent is about to write. It
26
+ # does NOT catch:
27
+ # - Credentials reformatted (base64'd, split across lines, etc.)
28
+ # - Read tools (read of ``.env`` is allowed by default; the
29
+ # sensitive-path read denies live in ``_host.yaml`` for the
30
+ # cases that DO matter)
31
+ # - Token exfil via outbound HTTP that happens not to use
32
+ # ``Bash``/``Write`` (use ``capability/network`` for that —
33
+ # planned)
34
+ #
35
+ # Include via:
36
+ # include:
37
+ # - sponsio:capability/credentials
38
+ #
39
+ # Tool naming:
40
+ # The pack uses canonical ``write`` / ``edit`` / ``apply_patch``
41
+ # for the write surface. Claude Code's ``_host.yaml`` adds
42
+ # ``write: Write`` / ``edit: Edit`` / ``apply_patch: MultiEdit``
43
+ # to its ``tool_rename`` block; OpenClaw's ``_host_openclaw.yaml``
44
+ # inherits canonical names directly.
45
+ #
46
+ # Source tag convention:
47
+ # library:tier1.credentials
48
+ # =============================================================================
49
+
50
+ version: "1"
51
+
52
+ tools:
53
+ - name: write
54
+ description: "Write or overwrite a file (placeholder — replace with your tool's name)"
55
+ params: "path: str, content: str"
56
+ - name: edit
57
+ description: "In-place edit of an existing file"
58
+ params: "path: str, new_string: str"
59
+ - name: apply_patch
60
+ description: "Apply a unified diff to a file"
61
+ params: "path: str, diff: str"
62
+
63
+ agents:
64
+ "*":
65
+ contracts:
66
+
67
+ # =================================================================
68
+ # § 1 — Block credential shapes in file-write CONTENT
69
+ # =================================================================
70
+ #
71
+ # The regex inventory targets the most common shapes that
72
+ # `git secrets`, gitleaks, trufflehog and friends recognise.
73
+ # Conservative on purpose: false positives here only block one
74
+ # write — the user can re-prompt with a redacted version.
75
+ # False negatives mean the secret ships, which is much worse.
76
+
77
+ - desc: "Block writes containing AWS / GCP / Azure / cloud creds"
78
+ E:
79
+ pattern: arg_blacklist
80
+ args:
81
+ - write
82
+ - content
83
+ - - "AKIA[A-Z0-9]{16}" # AWS access key
84
+ - "ASIA[A-Z0-9]{16}" # AWS temp creds
85
+ - "(?i)aws_secret_access_key\\s*=\\s*[A-Za-z0-9/+=]{40}"
86
+ - "AIza[A-Za-z0-9_-]{35}" # Google API key
87
+ - "ya29\\.[A-Za-z0-9_-]{20,}" # Google OAuth
88
+ source: "library:tier1.credentials"
89
+
90
+ - desc: "Block writes containing GitHub tokens"
91
+ E:
92
+ pattern: arg_blacklist
93
+ args:
94
+ - write
95
+ - content
96
+ - - "ghp_[A-Za-z0-9]{36,}" # personal access
97
+ - "ghu_[A-Za-z0-9]{36,}" # OAuth user
98
+ - "ghs_[A-Za-z0-9]{36,}" # server
99
+ - "gho_[A-Za-z0-9]{36,}" # OAuth app
100
+ - "github_pat_[A-Za-z0-9_]{82}" # fine-grained PAT
101
+ source: "library:tier1.credentials"
102
+
103
+ - desc: "Block writes containing payment-processor / SaaS API keys"
104
+ E:
105
+ pattern: arg_blacklist
106
+ args:
107
+ - write
108
+ - content
109
+ # Two key-prefix shapes co-exist in the wild:
110
+ # underscore-style (Stripe): sk_live_<base64ish>
111
+ # dash-style (OpenAI / Anthropic): sk-proj-<base64-with-dashes>
112
+ # Both random suffixes are >= 20 chars in practice.
113
+ - - "sk_(live|test)_[A-Za-z0-9]{20,}" # Stripe
114
+ - "sk-(live|test|proj|ant)-[A-Za-z0-9_-]{20,}" # OpenAI / Anthropic
115
+ - "rk_(live|test)_[A-Za-z0-9]{20,}" # Stripe restricted
116
+ - "xox[baprs]-[A-Za-z0-9-]{10,}" # Slack
117
+ - "SG\\.[A-Za-z0-9_-]{22}\\.[A-Za-z0-9_-]{43}" # SendGrid
118
+ - "key-[a-f0-9]{32}" # Mailgun
119
+ source: "library:tier1.credentials"
120
+
121
+ - desc: "Block writes containing private keys / SSH material"
122
+ E:
123
+ pattern: arg_blacklist
124
+ args:
125
+ - write
126
+ - content
127
+ - - "-----BEGIN\\s+(RSA|OPENSSH|EC|DSA|PGP)\\s+PRIVATE KEY"
128
+ - "-----BEGIN\\s+ENCRYPTED\\s+PRIVATE KEY"
129
+ source: "library:tier1.credentials"
130
+
131
+ # =================================================================
132
+ # § 2 — Mirror rules for in-place edit (Claude Code's `Edit`)
133
+ # =================================================================
134
+ #
135
+ # Editing is the same threat surface as Write — sub-agents that
136
+ # leak secrets often do so by editing a README in place rather
137
+ # than creating a new file. Same regex inventory; pinned to
138
+ # ``new_string`` (the canonical `edit` tool's payload field).
139
+
140
+ - desc: "Block edits containing AWS / GCP / Azure / cloud creds"
141
+ E:
142
+ pattern: arg_blacklist
143
+ args:
144
+ - edit
145
+ - new_string
146
+ - - "AKIA[A-Z0-9]{16}"
147
+ - "ASIA[A-Z0-9]{16}"
148
+ - "(?i)aws_secret_access_key\\s*=\\s*[A-Za-z0-9/+=]{40}"
149
+ - "AIza[A-Za-z0-9_-]{35}"
150
+ - "ya29\\.[A-Za-z0-9_-]{20,}"
151
+ source: "library:tier1.credentials"
152
+
153
+ - desc: "Block edits containing GitHub tokens"
154
+ E:
155
+ pattern: arg_blacklist
156
+ args:
157
+ - edit
158
+ - new_string
159
+ - - "ghp_[A-Za-z0-9]{36,}"
160
+ - "ghu_[A-Za-z0-9]{36,}"
161
+ - "ghs_[A-Za-z0-9]{36,}"
162
+ - "gho_[A-Za-z0-9]{36,}"
163
+ - "github_pat_[A-Za-z0-9_]{82}"
164
+ source: "library:tier1.credentials"
165
+
166
+ - desc: "Block edits containing payment-processor / SaaS API keys"
167
+ E:
168
+ pattern: arg_blacklist
169
+ args:
170
+ - edit
171
+ - new_string
172
+ - - "sk_(live|test)_[A-Za-z0-9]{20,}"
173
+ - "sk-(live|test|proj|ant)-[A-Za-z0-9_-]{20,}"
174
+ - "rk_(live|test)_[A-Za-z0-9]{20,}"
175
+ - "xox[baprs]-[A-Za-z0-9-]{10,}"
176
+ - "SG\\.[A-Za-z0-9_-]{22}\\.[A-Za-z0-9_-]{43}"
177
+ - "key-[a-f0-9]{32}"
178
+ source: "library:tier1.credentials"
179
+
180
+ - desc: "Block edits containing private keys / SSH material"
181
+ E:
182
+ pattern: arg_blacklist
183
+ args:
184
+ - edit
185
+ - new_string
186
+ - - "-----BEGIN\\s+(RSA|OPENSSH|EC|DSA|PGP)\\s+PRIVATE KEY"
187
+ - "-----BEGIN\\s+ENCRYPTED\\s+PRIVATE KEY"
188
+ source: "library:tier1.credentials"
@@ -0,0 +1,141 @@
1
+ # =============================================================================
2
+ # sponsio/contracts/capability/database.yaml
3
+ #
4
+ # Capability pack — destructive database operations via shell. Include
5
+ # when your agent exposes a tool that runs arbitrary shell commands
6
+ # (`exec`, `bash`, `Bash`, `run_command`, …) and the agent has database
7
+ # credentials in its environment.
8
+ #
9
+ # Real-world incidents this pack defends against:
10
+ #
11
+ # - Replit agent (Jul 2025): deleted live production DB during a code
12
+ # freeze, affecting 1,200+ companies. The model executed
13
+ # ``psql -c "DROP DATABASE prod"`` after misinterpreting a
14
+ # freeze instruction. Highest-profile data-loss incident from an
15
+ # LLM agent to date.
16
+ # - Anecdotal: agents running migration tools at the wrong scope —
17
+ # ``alembic downgrade base`` rolling back to an empty schema.
18
+ # - Anecdotal: agents using ``redis-cli FLUSHALL`` to "reset state"
19
+ # during debugging, wiping a shared dev cache.
20
+ #
21
+ # This pack is shell-only. For per-MCP-server rules (e.g.
22
+ # ``mcp__postgres__execute_sql.statement``), generate a per-plugin
23
+ # library via ``sponsio plugin scan --introspect`` against that
24
+ # server.
25
+ #
26
+ # Include via:
27
+ # include:
28
+ # - sponsio:capability/database
29
+ #
30
+ # Tool naming:
31
+ # The pack uses canonical ``exec``. Rename if your agent's shell
32
+ # tool has a different name — Claude Code's ``Bash`` is auto-handled
33
+ # by the ``_host.yaml`` library's ``tool_rename:`` block.
34
+ #
35
+ # Source tag convention:
36
+ # library:tier1.database
37
+ # =============================================================================
38
+
39
+ version: "1"
40
+
41
+ tools:
42
+ - name: exec
43
+ description: "Shell command execution (placeholder — replace with your tool's real name)"
44
+ params: "command: str"
45
+
46
+ agents:
47
+ "*":
48
+ contracts:
49
+
50
+ # =================================================================
51
+ # § 1 — Destructive SQL via shell (psql / mysql / sqlite3 / ...)
52
+ # =================================================================
53
+
54
+ - desc: "Ban DROP DATABASE / DROP TABLE / DROP SCHEMA via shell"
55
+ E:
56
+ pattern: arg_blacklist
57
+ args:
58
+ - exec
59
+ - command
60
+ # Word boundaries on either side to avoid matching prose
61
+ # like ``"how to drop a table"``; case-insensitive because
62
+ # SQL is conventionally uppercase but agents often emit
63
+ # lowercase.
64
+ - - "(?i)\\bdrop\\s+(database|table|schema|view|index)\\b"
65
+ source: "library:tier1.database"
66
+
67
+ - desc: "Ban TRUNCATE TABLE via shell (whole-table wipe)"
68
+ E:
69
+ pattern: arg_blacklist
70
+ args:
71
+ - exec
72
+ - command
73
+ # Require the literal "TABLE" keyword to avoid colliding
74
+ # with the unrelated POSIX ``truncate`` command (which
75
+ # extends/shrinks files via ``truncate -s N file``).
76
+ - - "(?i)\\btruncate\\s+table\\s+\\w+"
77
+ source: "library:tier1.database"
78
+
79
+ - desc: "Ban unbounded DELETE FROM (no WHERE clause)"
80
+ E:
81
+ pattern: arg_blacklist
82
+ args:
83
+ - exec
84
+ - command
85
+ # ``DELETE FROM users;`` matches; ``DELETE FROM users
86
+ # WHERE id=1;`` does not, because the table name isn't
87
+ # immediately followed by a terminator. Catches the
88
+ # canonical "wipe a whole table" foot-gun without false-
89
+ # positing real DELETE-by-key statements.
90
+ - - "(?i)\\bdelete\\s+from\\s+\\w+\\s*;"
91
+ source: "library:tier1.database"
92
+
93
+ # =================================================================
94
+ # § 2 — Destructive DB CLI tools
95
+ # =================================================================
96
+
97
+ - desc: "Ban dropdb / mysqladmin drop / redis FLUSHALL / FLUSHDB"
98
+ E:
99
+ pattern: arg_blacklist
100
+ args:
101
+ - exec
102
+ - command
103
+ - - "(?i)\\bdropdb\\b"
104
+ - "(?i)\\bmysqladmin\\b.{0,80}\\bdrop\\b"
105
+ - "(?i)\\bredis-cli\\b.{0,80}\\b(flushall|flushdb)\\b"
106
+ - "(?i)\\bmongo\\s.{0,80}\\bdropDatabase\\s*\\("
107
+ source: "library:tier1.database"
108
+
109
+ - desc: "Ban migration rollback to empty schema"
110
+ E:
111
+ pattern: arg_blacklist
112
+ args:
113
+ - exec
114
+ - command
115
+ # ``downgrade base`` rolls schema back to the very
116
+ # beginning of migration history — irreversible without
117
+ # backups. Single-step downgrades (``-1``) stay allowed.
118
+ - - "(?i)\\balembic\\s+downgrade\\s+base\\b"
119
+ - "(?i)\\bflask\\s+db\\s+downgrade\\s+base\\b"
120
+ - "(?i)\\bdjango-admin\\s+flush\\b"
121
+ source: "library:tier1.database"
122
+
123
+ # =================================================================
124
+ # § 3 — Deletion of database data directories
125
+ # =================================================================
126
+
127
+ - desc: "Ban deletion of database data directories"
128
+ E:
129
+ pattern: arg_blacklist
130
+ args:
131
+ - exec
132
+ - command
133
+ # Common data-dir locations across distros; covers the
134
+ # "rm -rf /var/lib/postgresql/data" foot-gun that the
135
+ # capability/shell pack's ``rm -rf /`` rule misses
136
+ # because the path doesn't end at the root delimiter.
137
+ - - "rm\\s+-[rRf]+\\s+/var/lib/(postgresql|mysql|mongodb|redis|elasticsearch|cassandra|couchdb)\\b"
138
+ - "rm\\s+-[rRf]+\\s+/var/data/(postgresql|mysql|mongodb)\\b"
139
+ - "rm\\s+-[rRf]+\\s+/data/db\\b"
140
+ - "rm\\s+-[rRf]+\\s+/opt/(postgresql|mysql|mongodb)\\b"
141
+ source: "library:tier1.database"
@@ -0,0 +1,101 @@
1
+ # =============================================================================
2
+ # sponsio/contracts/capability/filesystem-strict.yaml
3
+ #
4
+ # Capability pack — strict workspace scoping for filesystem tools. Add
5
+ # alongside ``sponsio:capability/filesystem`` when you want every
6
+ # read/write/edit/apply_patch confined to an explicit workspace
7
+ # prefix.
8
+ #
9
+ # Why this pack is opt-in (not part of the base ``capability/filesystem``):
10
+ #
11
+ # - These rules require an absolute ``<workspace>/`` placeholder
12
+ # resolved at load time. Configs without a ``workspace:`` field
13
+ # can't satisfy them and produce silent "no path matched"
14
+ # evaluations on every call.
15
+ # - Recorded-trajectory demos and replay test fixtures often use
16
+ # RELATIVE paths (``src/components/UserList.tsx``). ``scope_limit``
17
+ # interprets these as outside the workspace, which generates
18
+ # "WOULD-BLOCK" noise on every benign read in observe mode and
19
+ # wedges the agent at step 1 in enforce mode.
20
+ # - For agents whose actual filesystem footprint is broad
21
+ # (CI/CD pipelines, system-administration assistants, monorepo
22
+ # refactor tools), workspace scope is wrong-by-design — they
23
+ # legitimately operate across many directories.
24
+ #
25
+ # In short: the sensitive-path blacklists in the base pack are the
26
+ # universal "every agent needs this" rules. Workspace scoping is
27
+ # the opinionated "I know my agent stays in one tree" addition.
28
+ # Include this pack when (a) your agent does stay in one tree AND
29
+ # (b) your traces use absolute paths under that tree.
30
+ #
31
+ # Include via:
32
+ # include:
33
+ # - sponsio:capability/filesystem # base — credential blacklists
34
+ # - sponsio:capability/filesystem-strict # this pack — workspace scope
35
+ #
36
+ # Source tag convention:
37
+ # library:tier1.filesystem-strict
38
+ # =============================================================================
39
+
40
+ version: "1"
41
+
42
+ agents:
43
+ "*":
44
+ contracts:
45
+
46
+ # =================================================================
47
+ # Workspace scoping — writes / edits / apply_patch.
48
+ #
49
+ # ``<workspace>/`` is a literal placeholder. The integration
50
+ # layer (or a hand-edited config) substitutes the actual root
51
+ # before load. Without resolution, scope_limit on relative
52
+ # paths is a silent always-pass.
53
+ # =================================================================
54
+
55
+ - desc: "Writes restricted to workspace"
56
+ E:
57
+ pattern: scope_limit
58
+ args:
59
+ - write
60
+ - ["<workspace>/"]
61
+ source: "library:tier1.filesystem-strict"
62
+
63
+ - desc: "In-place edits restricted to workspace"
64
+ E:
65
+ pattern: scope_limit
66
+ args:
67
+ - edit
68
+ - ["<workspace>/"]
69
+ source: "library:tier1.filesystem-strict"
70
+
71
+ - desc: "Patch application restricted to workspace"
72
+ E:
73
+ pattern: scope_limit
74
+ args:
75
+ - apply_patch
76
+ - ["<workspace>/"]
77
+ source: "library:tier1.filesystem-strict"
78
+
79
+ # Read scope is broader than write scope: agents legitimately
80
+ # inspect system state (/etc/hosts, /var/log/*), link headers
81
+ # (/usr/include/), and read stdlib for grounding. The
82
+ # sensitive-path blacklist in the base ``filesystem`` pack
83
+ # keeps secrets hard-denied under any of these roots.
84
+ - desc: "Reads restricted to workspace, /tmp, and read-only system paths"
85
+ E:
86
+ pattern: scope_limit
87
+ args:
88
+ - read
89
+ - - "<workspace>/"
90
+ - "/tmp/"
91
+ - "/etc/"
92
+ - "/var/log/"
93
+ - "/usr/include/"
94
+ - "/usr/local/include/"
95
+ - "/usr/lib/"
96
+ - "/usr/local/lib/"
97
+ - "/usr/share/"
98
+ - "/opt/"
99
+ - "/proc/"
100
+ - "/sys/"
101
+ source: "library:tier1.filesystem-strict"
@@ -0,0 +1,239 @@
1
+ # =============================================================================
2
+ # sponsio/contracts/capability/filesystem.yaml
3
+ #
4
+ # Capability pack — filesystem access. Include when your agent exposes
5
+ # read / write / edit / apply_patch tools against the host filesystem.
6
+ #
7
+ # Real-world incidents this pack defends against:
8
+ #
9
+ # - OpenClaw "weather-skill" incident: skill exfiltrated
10
+ # ~/.clawdbot/.env, leaking paid AI API keys.
11
+ # - OpenClaw AMOS payload: stole SSH keys, keychain, browser creds.
12
+ # - Cursor forum (Apr 2024 → Dec 2025): `.cursorignore` not honored in
13
+ # Auto Context; .env content silently sent to AI server.
14
+ # - Claude Code Issue #10077: recursive delete wiped /home files.
15
+ # - OpenClaw agent editing its own AGENTS.md / SOUL.md bootstrap files
16
+ # → persistent-prompt-injection at bootstrap time.
17
+ #
18
+ # Tool name conventions in this file:
19
+ # - read, write, edit, apply_patch (OpenClaw / Claude Code default)
20
+ # Rename to match your agent (e.g. Cursor uses edit_file/read_file).
21
+ #
22
+ # Include via:
23
+ # include:
24
+ # - sponsio:capability/filesystem
25
+ #
26
+ # Source tag convention:
27
+ # library:tier1.filesystem
28
+ # =============================================================================
29
+
30
+ version: "1"
31
+
32
+ tools:
33
+ - name: read
34
+ description: "Read file contents"
35
+ params: "path: str"
36
+ - name: write
37
+ description: "Create or overwrite a file"
38
+ params: "path: str, content: str"
39
+ - name: edit
40
+ description: "In-place edit of an existing file"
41
+ params: "path: str, patch: str"
42
+ - name: apply_patch
43
+ description: "Apply a unified diff"
44
+ params: "path: str, diff: str"
45
+
46
+ agents:
47
+ "*":
48
+ contracts:
49
+
50
+ # =================================================================
51
+ # § 1 — Sensitive-path hard denies
52
+ #
53
+ # These paths never have a legitimate reason to appear in an agent
54
+ # trace. If the agent needs one of them (e.g. a git credential
55
+ # rotator that legitimately reads .aws/credentials), the including
56
+ # config overrides this section.
57
+ # =================================================================
58
+
59
+ # The .env regex deliberately *excludes* the conventional
60
+ # non-secret variants (.env.example / .env.sample / .env.template
61
+ # / .env.dist) — those files exist to be committed to git and
62
+ # serve as documentation of expected variables. Blocking them
63
+ # would generate noisy false positives on day 1, which is the
64
+ # fastest way to get a security pack disabled. All other
65
+ # `.env` and `.env.<suffix>` paths are still blocked.
66
+ #
67
+ # `crontab` is end-anchored to avoid matching paths like
68
+ # `/projects/crontab-tests/` or `mycrontab.txt`.
69
+ - desc: "Deny reads of SSH keys, AWS credentials, browser keychains, dotenv secrets"
70
+ E:
71
+ pattern: arg_blacklist
72
+ args:
73
+ - read
74
+ - path
75
+ - - "(^|/)\\.ssh/"
76
+ - "(^|/)\\.aws/credentials"
77
+ - "(^|/)\\.aws/config"
78
+ - "(^|/)\\.env(\\.(?!example$|sample$|template$|dist$)[\\w.-]+)?$"
79
+ - "(^|/)\\.netrc"
80
+ - "(^|/)\\.pgpass"
81
+ - "(^|/)\\.kube/config"
82
+ - "(^|/)\\.docker/config\\.json"
83
+ - "(^|/)Library/Keychains"
84
+ - "(^|/)\\.gnupg/"
85
+ - "(^|/)id_rsa($|\\.)"
86
+ - "(^|/)id_ed25519($|\\.)"
87
+ # /etc/ is permitted for reads in §2 (hosts, resolv.conf,
88
+ # os-release are routinely needed for diagnostics) but
89
+ # these specific entries under /etc hold credentials or
90
+ # escalation config and must stay hard-denied:
91
+ - "^/etc/shadow($|/)"
92
+ - "^/etc/sudoers($|\\.d/|$)"
93
+ - "^/etc/ssh/ssh_host_"
94
+ - "^/etc/ssl/private/"
95
+ - "^/etc/krb5\\.keytab$"
96
+ source: "library:tier1.filesystem"
97
+
98
+ - desc: "Deny writes / edits into sensitive paths (prevent persistence or cred overwrite)"
99
+ E:
100
+ pattern: arg_blacklist
101
+ args:
102
+ - write
103
+ - path
104
+ - - "(^|/)\\.ssh/"
105
+ - "(^|/)\\.aws/"
106
+ - "(^|/)\\.bashrc$"
107
+ - "(^|/)\\.zshrc$"
108
+ - "(^|/)\\.profile$"
109
+ - "(^|/)crontab$"
110
+ - "(^|/)LaunchAgents/"
111
+ - "(^|/)LaunchDaemons/"
112
+ - "/etc/"
113
+ - "/usr/local/bin/"
114
+ source: "library:tier1.filesystem"
115
+
116
+ - desc: "Same denial applies to in-place edits"
117
+ E:
118
+ pattern: arg_blacklist
119
+ args:
120
+ - edit
121
+ - path
122
+ - - "(^|/)\\.ssh/"
123
+ - "(^|/)\\.aws/"
124
+ - "(^|/)\\.bashrc$"
125
+ - "(^|/)\\.zshrc$"
126
+ - "(^|/)\\.profile$"
127
+ - "(^|/)crontab$"
128
+ - "(^|/)LaunchAgents/"
129
+ - "(^|/)LaunchDaemons/"
130
+ - "/etc/"
131
+ source: "library:tier1.filesystem"
132
+
133
+ - desc: "And to unified-diff patches"
134
+ E:
135
+ pattern: arg_blacklist
136
+ args:
137
+ - apply_patch
138
+ - path
139
+ - - "(^|/)\\.ssh/"
140
+ - "(^|/)\\.aws/"
141
+ - "/etc/"
142
+ source: "library:tier1.filesystem"
143
+
144
+ # =================================================================
145
+ # § 2 — Workspace scoping (moved to filesystem-strict)
146
+ #
147
+ # The four ``scope_limit`` rules that used to live here
148
+ # (Writes / Edits / Patch / Reads restricted to workspace +
149
+ # system-read paths) are now in
150
+ # ``sponsio:capability/filesystem-strict``. Reason: they
151
+ # require an absolute workspace prefix that many real agents
152
+ # don't have, and they false-positive on relative-path traces
153
+ # (e.g. ``src/components/UserList.tsx``).
154
+ #
155
+ # Add the strict pack alongside this one when you actually
156
+ # want workspace bounding:
157
+ #
158
+ # include:
159
+ # - sponsio:capability/filesystem
160
+ # - sponsio:capability/filesystem-strict
161
+ # =================================================================
162
+
163
+ # =================================================================
164
+ # § 3 — Operational hygiene
165
+ # =================================================================
166
+
167
+ - desc: "Must read a file before editing it (no blind patches)"
168
+ E:
169
+ pattern: must_precede
170
+ args: [read, edit]
171
+ source: "library:tier1.filesystem"
172
+
173
+ - desc: "Must read a file before apply_patch (no blind diffs)"
174
+ E:
175
+ pattern: must_precede
176
+ args: [read, apply_patch]
177
+ source: "library:tier1.filesystem"
178
+
179
+ # =================================================================
180
+ # § 4 — Self-modification guardrails
181
+ #
182
+ # Agents with a persistent workspace often have "bootstrap" files
183
+ # whose contents get injected into the system prompt every
184
+ # session (OpenClaw: AGENTS.md, SOUL.md, IDENTITY.md, USER.md;
185
+ # Claude Code: CLAUDE.md; Cursor: .cursorrules). The agent
186
+ # editing these is persistent prompt injection — an attacker who
187
+ # compromises one session can seed instructions that fire every
188
+ # future session.
189
+ #
190
+ # We gate self-modification behind a confirm_reconfirmed marker.
191
+ # =================================================================
192
+
193
+ - desc: "Editing bootstrap / system-prompt files requires human confirmation"
194
+ E:
195
+ ltl: 'G(called_with(edit, "(AGENTS|SOUL|IDENTITY|USER|CLAUDE|\\.cursorrules)\\.md?") -> count(confirm_reconfirmed) >= count_with(edit, "(AGENTS|SOUL|IDENTITY|USER|CLAUDE|\\.cursorrules)\\.md?"))'
196
+ source: "library:tier1.filesystem"
197
+
198
+ - desc: "apply_patch against bootstrap files requires confirmation"
199
+ E:
200
+ ltl: 'G(called_with(apply_patch, "(AGENTS|SOUL|IDENTITY|USER|CLAUDE|\\.cursorrules)\\.md?") -> count(confirm_reconfirmed) >= count_with(apply_patch, "(AGENTS|SOUL|IDENTITY|USER|CLAUDE|\\.cursorrules)\\.md?"))'
201
+ source: "library:tier1.filesystem"
202
+
203
+ # =================================================================
204
+ # § 5 — Data-leak prevention
205
+ #
206
+ # Generic no-data-leak from read → external sinks. The including
207
+ # config must name the external sinks (send_message, http_post,
208
+ # etc.) — we can't enumerate them here since sink inventory is
209
+ # agent-specific. The `send_message` form below is the most
210
+ # common instance and OpenClaw-derived; it's harmless to keep
211
+ # here because if the agent doesn't have send_message the formula
212
+ # is vacuously satisfied.
213
+ # =================================================================
214
+
215
+ - desc: "Data read from filesystem must not flow to outbound messages"
216
+ E:
217
+ pattern: no_data_leak
218
+ args: [read, send_message]
219
+ source: "library:tier1.filesystem"
220
+
221
+ # -----------------------------------------------------------------------------
222
+ # Integration requirements
223
+ # -----------------------------------------------------------------------------
224
+ #
225
+ # - `<workspace>/` is a literal prefix — resolve it at include time or
226
+ # pre-process the YAML with a sed substitution before handing to
227
+ # config.load(). A cleaner fix is a resolver hook in the include
228
+ # mechanism; tracked as future work.
229
+ #
230
+ # - `confirm_reconfirmed` must be emitted by the integration on human
231
+ # approval. Same marker convention as capability/shell.yaml.
232
+ #
233
+ # - If your agent's filesystem tools aren't named read/write/edit/
234
+ # apply_patch, rename them at include time or at config-load.
235
+ #
236
+ # - The sensitive-path blacklists are conservative. Agents with a
237
+ # legitimate reason to touch one of those paths (e.g. an SSH key
238
+ # rotator, a cron editor) should narrow the blacklist in their own
239
+ # config rather than removing this file from the include chain.