Deception and Anti-Analysis¶
These rules target the reviewer, not the shell. R012 and R013 are the two FATAL rules: text addressed to whoever reads the PKGBUILD, and codepoints that make displayed text differ from executed text. Both hard-stop the score at 100, and both are tripwires. When one fires the package is almost certainly malicious; when neither fires, nothing has been established.
R119 and the reserved R023/R024 are the inverse direction: the recipe checking whether it is being watched. A build script that probes for a debugger, a VM or a CI runner has no legitimate reason to care.
See the rule system reference for the field table, the severity weights and the reserved identifier ranges.
R012: Prompt Injection Detection¶
- Target:
resolved - Severity: FATAL (hard-stop at 100, weight 0)
- Category:
injection - Pattern:
\b(?:ignore|disregard|forget|override|bypass)\s+(?:all\s+|any\s+|the\s+)*(?:previous|above|prior|earlier|preceding|foregoing|existing)\s+(?:\w+\s+){0,2}(?:instructions?|commands?|input|context|rules?|prompts?|guidelines?|checks?)|^[^\S\n]*(?:#[^\S\n]*)?(?:system|assistant)[^\S\n]*:[^\S\n]*\S|</?(?:system|instructions?|admin|prompt|assistant)\s*>|\byou\s+are\s+(?:an?|the)\s+[^.\n]{0,48}?(?:model|assistant|ai\b)|\bnew\s+instructions?\s*:|\bdo(?:\s+not|n['’]t)\s+(?:flag|warn|analy[sz]e|review|scan)\b|\bdo(?:\s+not|n['’]t)\s+report\s+(?:any\s+|the\s+)?(?:security|issues?|concerns?|problems?|findings?|warnings?|anything)\b|\b(?:mark|classify|report|treat|label|approve)\b[^.\n]{0,24}?\bas\s+(?:safe|benign|clean|harmless|trusted|ok)\b|\b(?:claude|chatgpt|gpt-?[0-9]?|copilot|gemini|llm|ai\s+assistant)\b[^.\n]{0,60}?\b(?:ignore|approve|skip|overlook|flag)\b - Comments: scanned (
include_comments) - Description: Detects text addressed to whoever reads the PKGBUILD rather than to the shell that runs it: instruction overrides ("ignore the previous instructions"), role markers (
system:,assistant:), tag-like injections (<system>,<instructions>), personas ("you are a helpful model..."), suppression orders ("do not flag/warn/analyze") and pre-declared verdicts ("mark this as safe"). Comment lines are scanned, unlike every rule that describes what the shell executes, because the payload is always a comment. Calibrated at 22/22 injection fixtures with 0 fires across the 3,246-diff benign corpus. This is still a tripwire rule: when it fires the package is almost certainly malicious; when it does not, nothing can be concluded. Score hard-stops at 100 regardless of other signals.
R013: Unicode Bidi Override¶
- Target:
raw_line - Severity: FATAL (hard-stop at 100, weight 0)
- Category:
unicode - Pattern:
[\u202A-\u202E\u2066-\u2069\u2060-\u2064\U000E0000-\U000E007F]|(?<![^\x00-\x7F])[\u200B-\u200F\uFEFF](?![^\x00-\x7F])
The rule splits deceptive codepoints into two classes, because they are not equally suspicious.
Fires unconditionally: bidi overrides and isolates (U+202A-U+202E, U+2066-U+2069), invisible operators (U+2060-U+2064), and tag characters (U+E0000-U+E007F). None has a legitimate use in a build recipe. These are the characters that make displayed text differ from executed text.
Fires only between ASCII neighbours: zero-width and directional characters (U+200B-U+200F, U+FEFF). U+200B-U+200D are mandatory joiners in Malayalam, Lao, Devanagari and other scripts: a localized GenericName[ml]= line in a browser package legitimately contains U+200D. Because R013 is FATAL, firing on one scored an entirely benign package 100/100. Two packages in the benign corpus (brave-origin-bin, zen-browser-bin) did exactly this. Requiring ASCII on both sides preserves the attack (a joiner hidden inside an ASCII command or URL, such as https://evil.com<U+200D>/pkg.tar.gz) while dropping the false positive.
- Note: Score hard-stops at 100 regardless of other signals. The previous pattern omitted U+200E/U+200F, U+2060-U+2064 and the tag block, which is where the documented recall gap came from;
unicode.pyalready listed them.
R023: Strace detection attempt (TracerPid check)¶
- Target:
runtime(resolved execution path) - Severity: CRITICAL (weight 40)
- Category:
evasion - Pattern:
(?!)(never matches) - Description: Reading
/proc/self/statusTracerPidto detect a debugger or sandbox. Anti-analysis behaviour. Reservednever-matchruntime placeholder.
R024: Strace log truncated (possible flood evasion)¶
- Target:
runtime(resolved execution path) - Severity: HIGH (weight 25)
- Category:
evasion - Pattern:
(?!)(never matches) - Description: A beacon/timestamp flood that forces an audit log to truncate. Reserved
never-matchruntime placeholder; complements the R023 debugger probe.
R119: Anti-Analysis Check¶
- Severity: HIGH (weight 25)
- Category:
anti_analysis - Condition: A build or install function probes for a debugger (
TracerPid), a VM (systemd-detect-virt, DMI or hypervisor strings), a sandbox, or CI ($CI,$GITHUB_ACTIONS,$CONTAINER,/.dockerenv), from[patterns] anti_analysis_probes.
A build script checking whether it is being watched has no legitimate purpose.
Architecture and feature detection (uname -m, getconf) is not a probe and
does not fire.
Fire rate: 0 of 3246.