Skip to content

fix: classify js module and php suffixes as executable content - #480

Open
MohammedAlkindi wants to merge 1 commit into
NVIDIA:mainfrom
MohammedAlkindi:fix/executable-suffixes-js-php
Open

fix: classify js module and php suffixes as executable content#480
MohammedAlkindi wants to merge 1 commit into
NVIDIA:mainfrom
MohammedAlkindi:fix/executable-suffixes-js-php

Conversation

@MohammedAlkindi

Copy link
Copy Markdown

_EXECUTABLE_SUFFIXES (nested_artifacts.py:51) lists .js and .rb but not .mjs, .cjs, .jsx, .tsx, .mts, .cts, .php* or .rake, so is_executable_content returns False for files the scanner's own language maps already treat as script source: _JAVASCRIPT_EXTENSIONS (static_patterns_output_handling.py:76) lists all eight JS/TS forms, and _LANG_BY_EXT (static_patterns_deserialization.py:47) maps .php* and .rake.

That flag gates more than a label. mcp_least_privilege.py:481 returns early as a docs-only skill when nothing is executable, and nested_artifacts.py:984 sets concealed_executable only when it is true.

Three skills with byte-identical script bodies, differing only in extension, scanned with --no-llm. Before:

helper.rb    executable=True    score 19
helper.php   executable=False   score 15
helper.mjs   executable=False   score 15

After, all three are executable at score 19.

Those bodies deliberately carry no shebang. The magic-byte fallback already rescues shebang'd files, and the 0o111 fallback rescues anything carrying the exec bit, so what this changes is suffix-only scripts.

Unit suite 3943 to 3953 passed, the extra ten being the new tests, with an identical 23-failure set either side (pre-existing here: Windows symlink and release-tooling). ruff check and ruff format --check clean.

Added only suffixes an existing analyzer already recognises. .psm1, .pm, .vbs and .wsf are deliberately left out. Found by inspection, not a user report.

@mohgupta-ship-it
mohgupta-ship-it self-requested a review September 7, 2026 05:39
@mohgupta-ship-it

Copy link
Copy Markdown
Member

LGTM, waiting on rebase to pass

@mohgupta-ship-it

Copy link
Copy Markdown
Member

Powered by Codex: I checked the suffix-only additions against both SkillSpector's existing analyzer routing and the actual runtime semantics.

Short answer: these are all script-bearing / executable-capable suffixes, but they are not all unconditionally or directly executable merely because of the suffix.

  • .cjs and .mjs are the strongest cases: Node treats them as explicit CommonJS and ES-module runtime formats, respectively (Node.js packages documentation).
  • .cts and .mts can run directly on sufficiently new Node versions when they use supported erasable TypeScript syntax; otherwise they require a compiler or loader. Node maps them to CommonJS and ESM respectively (Node.js TypeScript documentation).
  • .jsx and .tsx are toolchain-dependent source. JSX normally requires transformation, and stock Node explicitly does not support .tsx (TypeScript JSX documentation).
  • .php is executable through PHP; .php3, .php4, .php5, and .phtml are legacy/configuration-dependent web-handler signals rather than universally executable extensions. PHP documents that server configuration controls which suffixes are parsed as PHP (PHP manual).
  • .rake contains executable Ruby and is loaded by Rake from conventional task directories (Rake documentation).

That means the PR reasonably closes an internal policy mismatch: these suffixes were already routed through SkillSpector's script analyzers, while is_executable_content() failed to mark them as executable-capable. It should still be described as a conservative security classification, not proof that a given file will execute on every host.

One concrete false-positive edge remains: Path(path).suffix classifies types.d.cts and types.d.mts as executable even though those are TypeScript declaration files, not runtime implementations. I recommend explicitly excluding .d.cts and .d.mts and adding regression tests. Apart from that declaration-file case, I did not find an added suffix that is wholly unrelated to executable code.

Signed-off-by: Mohammed Alkindi <alkndymhmd692@gmail.com>
@mohgupta-ship-it
mohgupta-ship-it force-pushed the fix/executable-suffixes-js-php branch from 95fe426 to a4bb9fc Compare September 7, 2026 10:16
@pytest.mark.parametrize(
"suffix",
[".cjs", ".cts", ".jsx", ".mjs", ".mts", ".tsx", ".php", ".phtml", ".rake"],
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One concrete false-positive edge remains: Path(path).suffix classifies types.d.cts and types.d.mts as executable even though those are TypeScript declaration files, not runtime implementations. I recommend explicitly excluding .d.cts and .d.mts and adding regression tests. Apart from that declaration-file case, I did not find an added suffix that is wholly unrelated to executable code.

Please handle this @MohammedAlkindi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants