


























@@ -0,0 +1,325 @@
1+/**
2+ * @name Managed proxy runtime mutation
3+ * @description Proxy-related process.env and GLOBAL_AGENT runtime mutations must stay in managed proxy owner scopes.
4+ * @kind problem
5+ * @problem.severity error
6+ * @precision high
7+ * @id js/openclaw/managed-proxy-runtime-mutation
8+ * @tags maintainability
9+ * security
10+ * external/cwe/cwe-441
11+ */
12+13+import javascript
14+15+predicate forbiddenEnvKey(string key) {
16+key =
17+[
18+"HTTP_PROXY",
19+"HTTPS_PROXY",
20+"http_proxy",
21+"https_proxy",
22+"NO_PROXY",
23+"no_proxy",
24+"GLOBAL_AGENT_HTTP_PROXY",
25+"GLOBAL_AGENT_HTTPS_PROXY",
26+"GLOBAL_AGENT_NO_PROXY",
27+"GLOBAL_AGENT_FORCE_GLOBAL_AGENT",
28+"OPENCLAW_PROXY_ACTIVE",
29+"OPENCLAW_PROXY_LOOPBACK_MODE"
30+]
31+}
32+33+predicate forbiddenGlobalAgentKey(string key) { key = ["HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY"] }
34+35+predicate relevantSourceFile(File file) {
36+exists(string path |
37+path = file.getRelativePath() and
38+path.regexpMatch("^(src|extensions)/.*\\.(ts|mts|js|mjs)$") and
39+not path.regexpMatch(".*\\.(test|spec)\\.(ts|mts|js|mjs)$") and
40+not path.regexpMatch(".*\\.(test-utils|test-harness|e2e-harness)\\.ts$") and
41+not path.regexpMatch(".*/test-support/.*") and
42+not path.regexpMatch(".*/vendor/.*") and
43+not path.regexpMatch(".*\\.min\\.js$") and
44+not path.regexpMatch("^extensions/diffs/assets/.*")
45+)
46+}
47+48+predicate namedExpr(Expr expr, string name) {
49+expr.getUnderlyingValue().(Identifier).getName() = name
50+}
51+52+predicate directProcessEnvExpr(Expr expr) {
53+exists(PropAccess access |
54+expr.getUnderlyingValue() = access and
55+access.getPropertyName() = "env" and
56+namedExpr(access.getBase(), "process")
57+)
58+}
59+60+predicate envAlias(Variable variable) {
61+exists(VariableDeclarator decl |
62+decl.getBindingPattern().getAVariable() = variable and
63+directProcessEnvExpr(decl.getInit())
64+)
65+or
66+exists(VariableDeclarator decl, ObjectPattern pattern, PropertyPattern property |
67+decl.getBindingPattern() = pattern and
68+namedExpr(decl.getInit(), "process") and
69+property = pattern.getAPropertyPattern() and
70+property.getName() = "env" and
71+property.getValuePattern().(BindingPattern).getAVariable() = variable
72+)
73+}
74+75+predicate processEnvExpr(Expr expr) {
76+directProcessEnvExpr(expr)
77+or
78+exists(VarAccess access |
79+expr.getUnderlyingValue() = access and
80+envAlias(access.getVariable())
81+)
82+}
83+84+predicate stringConst(Variable variable, string value) {
85+exists(VariableDeclarator decl |
86+decl.getBindingPattern().getAVariable() = variable and
87+value = decl.getInit().getStringValue()
88+)
89+}
90+91+predicate stringArrayContains(Variable variable, string value) {
92+exists(VariableDeclarator decl, ArrayExpr array, Expr element |
93+decl.getBindingPattern().getAVariable() = variable and
94+decl.getInit().getUnderlyingValue() = array and
95+element = array.getAnElement().getUnderlyingValue() and
96+value = element.getStringValue()
97+)
98+or
99+exists(VariableDeclarator decl, ArrayExpr array, SpreadElement spread, VarAccess access |
100+decl.getBindingPattern().getAVariable() = variable and
101+decl.getInit().getUnderlyingValue() = array and
102+spread = array.getAnElement().getUnderlyingValue() and
103+spread.getOperand().getUnderlyingValue() = access and
104+stringArrayContains(access.getVariable(), value)
105+)
106+}
107+108+predicate forbiddenEnvLoopVariable(Variable variable) {
109+exists(ForOfStmt loop, VarAccess domain, string key |
110+variable = loop.getAnIterationVariable() and
111+loop.getIterationDomain().getUnderlyingValue() = domain and
112+stringArrayContains(domain.getVariable(), key) and
113+forbiddenEnvKey(key)
114+)
115+}
116+117+predicate envKeyExprForbidden(Expr keyExpr) {
118+forbiddenEnvKey(keyExpr.getStringValue())
119+or
120+exists(VarAccess access, string key |
121+keyExpr.getUnderlyingValue() = access and
122+stringConst(access.getVariable(), key) and
123+forbiddenEnvKey(key)
124+)
125+or
126+exists(VarAccess access |
127+keyExpr.getUnderlyingValue() = access and
128+forbiddenEnvLoopVariable(access.getVariable())
129+)
130+}
131+132+predicate globalAgentKeyExprForbidden(Expr keyExpr) {
133+forbiddenGlobalAgentKey(keyExpr.getStringValue())
134+or
135+exists(VarAccess access, string key |
136+keyExpr.getUnderlyingValue() = access and
137+stringConst(access.getVariable(), key) and
138+forbiddenGlobalAgentKey(key)
139+)
140+}
141+142+predicate directGlobalExpr(Expr expr) {
143+namedExpr(expr, "global")
144+or
145+namedExpr(expr, "globalThis")
146+}
147+148+predicate globalAlias(Variable variable) {
149+exists(VariableDeclarator decl |
150+decl.getBindingPattern().getAVariable() = variable and
151+directGlobalExpr(decl.getInit())
152+)
153+}
154+155+predicate globalExpr(Expr expr) {
156+directGlobalExpr(expr)
157+or
158+exists(VarAccess access |
159+expr.getUnderlyingValue() = access and
160+globalAlias(access.getVariable())
161+)
162+}
163+164+predicate directGlobalAgentExpr(Expr expr) {
165+exists(PropAccess access |
166+expr.getUnderlyingValue() = access and
167+access.getPropertyName() = "GLOBAL_AGENT" and
168+globalExpr(access.getBase())
169+)
170+}
171+172+predicate globalAgentAlias(Variable variable) {
173+exists(VariableDeclarator decl |
174+decl.getBindingPattern().getAVariable() = variable and
175+directGlobalAgentExpr(decl.getInit())
176+)
177+}
178+179+predicate globalAgentExpr(Expr expr) {
180+directGlobalAgentExpr(expr)
181+or
182+exists(VarAccess access |
183+expr.getUnderlyingValue() = access and
184+globalAgentAlias(access.getVariable())
185+)
186+}
187+188+predicate envMutationTarget(Expr target) {
189+exists(PropAccess access |
190+target.getUnderlyingReference() = access and
191+processEnvExpr(access.getBase()) and
192+(
193+forbiddenEnvKey(access.getPropertyName())
194+or
195+envKeyExprForbidden(access.getPropertyNameExpr())
196+)
197+)
198+}
199+200+predicate globalAgentMutationTarget(Expr target) {
201+globalAgentExpr(target)
202+or
203+exists(PropAccess access |
204+target.getUnderlyingReference() = access and
205+globalAgentExpr(access.getBase()) and
206+(
207+forbiddenGlobalAgentKey(access.getPropertyName())
208+or
209+globalAgentKeyExprForbidden(access.getPropertyNameExpr())
210+)
211+)
212+}
213+214+predicate objectPropertyWithKey(Expr expr, string key) {
215+exists(ObjectExpr object, Property property |
216+expr.getUnderlyingValue() = object and
217+property = object.getAProperty() and
218+property.getName() = key
219+)
220+}
221+222+Expr managedProxyRuntimeMutation() {
223+exists(Assignment assignment |
224+result = assignment and
225+(
226+envMutationTarget(assignment.getTarget())
227+or
228+globalAgentMutationTarget(assignment.getTarget())
229+)
230+)
231+or
232+exists(DeleteExpr delete |
233+result = delete and
234+(
235+envMutationTarget(delete.getOperand())
236+or
237+globalAgentMutationTarget(delete.getOperand())
238+)
239+)
240+or
241+exists(MethodCallExpr call |
242+result = call and
243+namedExpr(call.getReceiver(), "Object") and
244+call.getMethodName() = "assign" and
245+(
246+processEnvExpr(call.getArgument(0)) and
247+exists(string key |
248+forbiddenEnvKey(key) and
249+objectPropertyWithKey(call.getArgument(1), key)
250+)
251+or
252+globalAgentExpr(call.getArgument(0)) and
253+exists(string key |
254+forbiddenGlobalAgentKey(key) and
255+objectPropertyWithKey(call.getArgument(1), key)
256+)
257+)
258+)
259+or
260+exists(MethodCallExpr call |
261+result = call and
262+namedExpr(call.getReceiver(), "Object") and
263+call.getMethodName() = "defineProperty" and
264+(
265+processEnvExpr(call.getArgument(0)) and
266+envKeyExprForbidden(call.getArgument(1))
267+or
268+globalAgentExpr(call.getArgument(0)) and
269+globalAgentKeyExprForbidden(call.getArgument(1))
270+)
271+)
272+}
273+274+predicate allowedFunctionOwnerScope(Expr mutation, string path, string functionName) {
275+exists(Function owner |
276+mutation.getFile().getRelativePath() = path and
277+owner.getFile() = mutation.getFile() and
278+owner.getName() = functionName and
279+mutation.getParent*() = owner.getBody()
280+)
281+}
282+283+predicate allowedMethodOwnerScope(Expr mutation, string path, string methodName) {
284+exists(MethodDeclaration method |
285+mutation.getFile().getRelativePath() = path and
286+method.getFile() = mutation.getFile() and
287+method.getDeclaringType().getName() + "." + method.getName() = methodName and
288+mutation.getParent*() = method.getBody().getBody()
289+)
290+}
291+292+predicate allowedManagedProxyRuntimeMutation(Expr mutation) {
293+allowedFunctionOwnerScope(mutation, "src/infra/net/proxy/proxy-lifecycle.ts", "applyProxyEnv")
294+or
295+allowedFunctionOwnerScope(mutation, "src/infra/net/proxy/proxy-lifecycle.ts", "restoreProxyEnv")
296+or
297+allowedFunctionOwnerScope(mutation, "src/infra/net/proxy/proxy-lifecycle.ts",
298+"restoreGlobalAgentRuntime")
299+or
300+allowedFunctionOwnerScope(mutation, "src/infra/net/proxy/proxy-lifecycle.ts",
301+"restoreNodeHttpStack")
302+or
303+allowedFunctionOwnerScope(mutation, "src/infra/net/proxy/proxy-lifecycle.ts",
304+"bootstrapNodeHttpStack")
305+or
306+allowedFunctionOwnerScope(mutation, "src/infra/net/proxy/proxy-lifecycle.ts",
307+"writeGlobalAgentNoProxy")
308+or
309+allowedFunctionOwnerScope(mutation, "src/infra/net/proxy/proxy-lifecycle.ts",
310+"disableGlobalAgentProxyForIpv6GatewayLoopback")
311+or
312+allowedMethodOwnerScope(mutation, "extensions/browser/src/browser/cdp-proxy-bypass.ts",
313+"NoProxyLeaseManager.acquire")
314+or
315+allowedMethodOwnerScope(mutation, "extensions/browser/src/browser/cdp-proxy-bypass.ts",
316+"NoProxyLeaseManager.release")
317+}
318+319+from Expr mutation
320+where
321+managedProxyRuntimeMutation() = mutation and
322+relevantSourceFile(mutation.getFile()) and
323+not allowedManagedProxyRuntimeMutation(mutation)
324+select mutation,
325+"Only managed proxy owner scopes may mutate proxy-related process.env or GLOBAL_AGENT runtime state."
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。