Commit ac621ab
committed
Security: close a critical injection and three broken invariants
An adversarial review found that three of eleven invariants did not hold as
written, and that in the generated workflow none of them were load-bearing at
all. Every case below was a working exploit before it was a test.
CRITICAL -- sync.mjs spliced the webhook's safeAddress raw into a JS source
string. A caller could close the string literal and append their own assemble()
declaration, which hoists over the real one and bypasses all eleven guards at
once, fully authoring the node's output. Verified against the real generated
workflow. Fixed twice over: the template is now substituted as a bare JSON
value rather than inside quotes, and a new gate-addr Condition rejects anything
that is not a 20-byte address before it reaches the code node at all.
I1 was broken. Nothing required the threshold to be >= 1, so threshold 0
returned executable:true with an empty signature blob -- and a NEGATIVE
threshold was worse, because slice(0, -5) counts from the end, so two real
signatures also became an empty blob. toBig accepted "-5" because BigInt does.
Counts now parse through toCount, which rejects negatives.
I7 was broken. It refused CONTRACT_SIGNATURE and APPROVED_HASH by reading
signatureType -- an optional field a hostile payload omits. Both schemes are
exactly 65 bytes, so they passed the shape check. v=0 is the dangerous one:
checkSignatures reads s as an offset and CALLS the address in r, an
attacker-controlled external call inside execTransaction. The guard now checks
the v byte, which cannot be omitted. The assertion already existed in
live-fixture.test.mjs; it just was not in the code.
I3 failed open. lower() maps undefined, null and "" to the same empty string,
so one stray "" in roster.json matched a missing safeAddress and opened the
gate for every run. Falsy entries are filtered and the address shape is checked
first.
drain.mjs had two gates that did not gate. Gate 2 printed "inner reverts" and
broadcast anyway -- real gas, nonce permanently consumed, nothing moved. Gate 3
asserted Response.ok, so a 2xx body carrying {success:false} passed what the
header calls a preflight. Both now stop. A refusal exits 3 so a wrapper can
tell it from an execution.
Also: the queue reads had no ordering, and the service defaults to newest-first
while the only executable entry is the LOWEST pending nonce -- so past 20
pending proposals gavel would have reported not-next-nonce forever, fail-closed
but silently wrong. The workflow's hydrate node was unauthenticated, which
would have turned a 401 into a plausible-looking empty queue. Malformed fields
now produce named refusals instead of throwing an undeclared tenth outcome.
Two tests were vacuous and are fixed. The case-insensitivity test compared an
all-1s address to itself and would have passed if matching were case-sensitive.
The test asserting the headline claim -- that the executor owns nothing --
compared the executor address against role handles like "O1", so it could never
fail; it now resolves roles to real addresses.
64 tests. The live blob still simulates SUCCESS against the real Safe.1 parent e6240cf commit ac621ab
7 files changed
Lines changed: 438 additions & 48 deletions
File tree
- scripts
- src
- test
- workflows
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
84 | 84 | | |
85 | 85 | | |
86 | 86 | | |
87 | | - | |
| 87 | + | |
88 | 88 | | |
89 | 89 | | |
90 | 90 | | |
| |||
99 | 99 | | |
100 | 100 | | |
101 | 101 | | |
102 | | - | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
103 | 105 | | |
104 | 106 | | |
105 | 107 | | |
| |||
113 | 115 | | |
114 | 116 | | |
115 | 117 | | |
116 | | - | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
117 | 130 | | |
118 | 131 | | |
119 | 132 | | |
| |||
141 | 154 | | |
142 | 155 | | |
143 | 156 | | |
144 | | - | |
145 | | - | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
146 | 167 | | |
147 | 168 | | |
148 | 169 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
74 | 74 | | |
75 | 75 | | |
76 | 76 | | |
77 | | - | |
78 | | - | |
79 | | - | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
80 | 91 | | |
81 | 92 | | |
82 | 93 | | |
| |||
94 | 105 | | |
95 | 106 | | |
96 | 107 | | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
97 | 114 | | |
98 | 115 | | |
99 | 116 | | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
100 | 124 | | |
101 | | - | |
| 125 | + | |
102 | 126 | | |
103 | 127 | | |
104 | 128 | | |
| |||
160 | 184 | | |
161 | 185 | | |
162 | 186 | | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
163 | 196 | | |
164 | 197 | | |
165 | 198 | | |
166 | | - | |
| 199 | + | |
167 | 200 | | |
168 | 201 | | |
169 | 202 | | |
170 | 203 | | |
171 | 204 | | |
172 | 205 | | |
173 | | - | |
| 206 | + | |
174 | 207 | | |
175 | 208 | | |
176 | 209 | | |
| |||
179 | 212 | | |
180 | 213 | | |
181 | 214 | | |
182 | | - | |
183 | | - | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
184 | 226 | | |
185 | 227 | | |
186 | 228 | | |
| |||
204 | 246 | | |
205 | 247 | | |
206 | 248 | | |
207 | | - | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
208 | 253 | | |
209 | 254 | | |
210 | 255 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
64 | | - | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
65 | 67 | | |
66 | 68 | | |
| 69 | + | |
67 | 70 | | |
68 | 71 | | |
69 | 72 | | |
70 | 73 | | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
71 | 91 | | |
72 | 92 | | |
73 | 93 | | |
| |||
104 | 124 | | |
105 | 125 | | |
106 | 126 | | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
107 | 150 | | |
108 | 151 | | |
109 | 152 | | |
| |||
140 | 183 | | |
141 | 184 | | |
142 | 185 | | |
143 | | - | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
144 | 192 | | |
145 | 193 | | |
146 | | - | |
147 | | - | |
148 | | - | |
149 | | - | |
| 194 | + | |
| 195 | + | |
150 | 196 | | |
151 | | - | |
152 | | - | |
| 197 | + | |
| 198 | + | |
153 | 199 | | |
154 | 200 | | |
155 | 201 | | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
156 | 218 | | |
157 | 219 | | |
158 | 220 | | |
159 | | - | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
160 | 229 | | |
161 | 230 | | |
162 | 231 | | |
| |||
168 | 237 | | |
169 | 238 | | |
170 | 239 | | |
171 | | - | |
172 | | - | |
173 | | - | |
174 | | - | |
175 | | - | |
176 | | - | |
177 | | - | |
| 240 | + | |
178 | 241 | | |
179 | 242 | | |
180 | 243 | | |
| |||
196 | 259 | | |
197 | 260 | | |
198 | 261 | | |
199 | | - | |
| 262 | + | |
200 | 263 | | |
201 | 264 | | |
202 | 265 | | |
| |||
224 | 287 | | |
225 | 288 | | |
226 | 289 | | |
227 | | - | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
228 | 299 | | |
229 | 300 | | |
230 | 301 | | |
| |||
253 | 324 | | |
254 | 325 | | |
255 | 326 | | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
256 | 342 | | |
257 | 343 | | |
258 | 344 | | |
| |||
277 | 363 | | |
278 | 364 | | |
279 | 365 | | |
280 | | - | |
| 366 | + | |
281 | 367 | | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
282 | 373 | | |
283 | 374 | | |
284 | 375 | | |
| |||
293 | 384 | | |
294 | 385 | | |
295 | 386 | | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
296 | 399 | | |
297 | 400 | | |
298 | 401 | | |
| |||
0 commit comments