SW-SKL-014: Obfuscated script code
Last updated 7 November 2026
| Fact | Value |
|---|---|
| Severity | Medium |
| Checks | Skill package |
| Malicious indicator | No |
| OWASP Agentic Top 10 | ASI04 |
| OWASP MCP Top 10 | None mapped |
| NIST SP 800-53 | SR-3 (provisional mapping to SP 800-53 base controls) |
| First shipped in | Scanner 0.1.0 |
What it detects
The rule reads the script files and fenced code blocks of the package line by line. A line is reported when it holds a run of at least 200 base64 characters or at least 100 pairs of hexadecimal digits (not on a line that starts with a comment mark # or //); twenty or more \x escapes in a row; a String.fromCharCode( call with ten or more arguments; ten or more chr(...) calls in a row, joined by plus signs or not; eval( or exec( whose first argument is not a quoted literal; or compile( followed by exec(.
Each line is one finding, with the line as evidence. The rule does not decode anything or judge the program: a long string, a pile of escapes or a call that runs a computed value are the marks of code written so that a reader cannot follow it, and each is tested by shape alone.
Why it matters
Plain scripts are written to be read. Code that builds itself from character codes, packs its logic in an encoded block or evaluates a computed string has been made unreadable for a reason, and a skill that does it gives a reviewer little to go on. The scanner maps this rule to OWASP ASI04, Agentic Supply Chain Vulnerabilities, and to NIST SP 800-53 control SR-3, Supply Chain Controls and Processes. A match is a request for a person to read the line, not proof that it is hostile.
Example
This Python script evaluates text it receives as an argument. The call has a computed first argument, which is enough:
.claude/skills/text-evaluator/SKILL.md
---
name: text-evaluator
description: Evaluates small expressions typed by the user.
license: MIT
version: 1.0.0
---
# Text evaluator
Run scripts/calc.py with the expression..claude/skills/text-evaluator/scripts/calc.py
import sys
expression = sys.argv[1]
print(eval(expression))The finding is on the line with the call.
How to fix
Replace the evaluation with code that does the one thing the script needs, such as parsing a number or reading a value from a fixed list. Move a large data block into a data file that is not run, and describe in the skill what it holds.
If it is a false positive
A script that embeds a small font, an icon or a test vector as encoded text may hold a long string, and a calculator skill may evaluate on purpose. Accept the finding with a note that says what the string is, or move it to a data file.
If the finding is not a problem in your case, accept it with a note: in the dashboard a manager or owner can accept a finding and the note is kept with it; with the scanner on its own, add it to the baseline file with a reason and an expiry date.