When Scanning Happens
Install time
Runs on every file in the skill bundle before the first byte is written. Applies to all four install paths:
skills.create, skills.update, skills.upload, and skills.import. A CRITICAL finding refuses the install with zero files written.Load time
Runs on the sanitized
SKILL.md body each time the skill is loaded into context. Catches a skill edited directly on disk after installation.What Gets Scanned
The content scanner checks skill text for six categories of dangerous patterns. At install time it reads every text member of the bundle — theSKILL.md body and support files such as references/, scripts/, templates/, and assets/. It does not scan or confine arbitrary code, MCP server executables, browser processes, or other integrations. Pattern matching can have false positives and false negatives, so operators must still review third-party skills and everything they instruct an agent to invoke.
Command Injection
Command Injection
Severity: CRITICALDetects attempts to run system commands through skill content. Attackers embed shell commands hoping the agent will execute them blindly.Examples caught:
$(command)— subshell execution- Backtick command substitution
eval()calls- Piped commands like
curl | bash
Environment Harvesting
Environment Harvesting
Severity: WARNDetects attempts to read sensitive environment variables where API keys, passwords, and secrets are often stored. Findings are logged but do not block skill loading by default.Examples caught:
printenvcommands- Reading
/proc/*/environ env | greppatterns that filter for specific secrets
Crypto Mining
Crypto Mining
Severity: CRITICALDetects cryptocurrency mining attempts that would hijack your server’s computing power.Examples caught:
stratum+tcp://mining pool URLs- Known miner binary names
- Mining pool domain references
Network Exfiltration
Network Exfiltration
Severity: mixed (WARN for piped downloads, CRITICAL for reverse shells)Detects attempts to send your data to external servers without authorization.Examples caught:
curl | shpatterns that download and execute remote code (WARN)wget -O- | bashdownload-and-run chains (WARN)- Reverse shell patterns that open a connection back to an attacker (CRITICAL)
Obfuscated Encoding
Obfuscated Encoding
Severity: mixed (WARN for long encoded blobs, CRITICAL for decode-and-execute chains)Detects suspiciously encoded content that may be hiding malicious instructions. Encoding is not always malicious, but large encoded blocks in a skill body are a red flag.Examples caught:
- Unusually long base64-encoded strings (WARN)
- Hex-encoded payloads (WARN)
base64 -d | bashdecode-and-execute patterns (CRITICAL)
XML Breakout
XML Breakout
Severity: CRITICALDetects attempts to escape the skill boundary and inject content directly into the agent’s system prompt.Examples caught:
</skill>close tags that try to end the skill context early<system>tags that attempt to hijack the prompt structure
The Sanitization Pipeline
In addition to scanning for threats, every prompt skill body goes through a four-step sanitization pipeline before it reaches the agent. This pipeline runs automatically on all skills, regardless of scan results.1
Strip HTML comments
Removes all
<!-- ... --> comment blocks. HTML comments are invisible in rendered content, making them a common way to hide malicious instructions that humans would not notice during review.2
Unicode normalization
Converts fancy characters to their standard forms using NFKC normalization. This prevents visual tricks where an attacker uses fullwidth or ligature characters that look identical to normal text but bypass pattern matching. For example, a fullwidth
eval looks like eval but would not match a simple text scan.3
Strip invisible characters
Removes zero-width Unicode characters like zero-width spaces, zero-width joiners, and Unicode tag characters. These are completely invisible in text but can carry hidden payloads or break security boundaries.
4
Enforce size limit
Truncates the skill body at the configured maximum length (default: 20,000 characters). If the body exceeds this limit, the excess is removed and a
[TRUNCATED] marker is appended. This prevents skills from overwhelming the agent’s context window.Bundle Structure Checks
Beyond pattern matching, the install gate checks the shape of the bundle — conditions a regular expression cannot see. These run first, so an oversized or malformed bundle is refused before any pattern matching happens. Refused outright:- No
SKILL.mdat the bundle root, or a manifest whose frontmatter does not parse or does not validate. Previously such a skill installed successfully and then silently failed to appear. - A non-prompt
type. Comis skills are prompt-only. - Unsafe member paths — absolute paths,
..traversal, drive-letter prefixes, or excessive nesting depth. - Symlink or hardlink members. A skill has no legitimate use for one.
- Binary or executable members, detected by file contents rather than by extension, so a payload named
notes.mdis still caught. - Bound breaches — too many files, too large a bundle, or too large a single file. See Configuration.
- An executable bit on a member that is not a recognized script type.
- Deep (but permitted) directory nesting.
- A manifest matched only case-insensitively (
skill.mdrather thanSKILL.md).
.skillignore file with gitignore-style patterns to exclude development artifacts from the structure checks. It never affects pattern scanning, and it cannot exclude SKILL.md.
Frontmatter Normalization
Skills authored for other agent runtimes often spell manifest fields in kebab-case (allowed-tools, argument-hint). The install gate maps these onto their Comis equivalents so such skills install rather than failing validation.
Fields with no Comis equivalent are dropped with a logged warning that names the key — never silently reinterpreted. Fields implying code execution (a script entrypoint, a run command, an install hook) are also dropped: the skill installs as its prompt body only, with a warning recording exactly what was discarded. If both spellings of a field are present, the Comis-native camelCase key wins and the other is reported.
What Happens When a Threat is Found
At install time the outcome depends on both the findings and where the skill came from. Comis assigns every install a trust tier from the call itself — never from anything the skill declares:
The tier and the verdict together decide what happens:
Confirm means the install is refused with a message naming every finding and its location, and you re-run the same call with
force: true to acknowledge them. Refuse cannot be overridden: force upgrades a confirmation, never a refusal. A CRITICAL finding in a skill you did not write is not installable, by any flag.
The asymmetry is deliberate. A CRITICAL pattern in a skill you authored is a mistake worth stopping for, but it is your content and your judgement. The same pattern arriving from a stranger is not.
At load time the rule is simpler: a CRITICAL finding blocks the skill from loading when contentScanning.blockOnCritical is enabled (the default). The agent never sees the content, and a log entry records what was found.
WARN findings never block a load, and never refuse an install — at most they ask for a confirmation. Review them and decide: obfuscated encoding, for example, may be legitimate, since some skills include base64 data for valid reasons.
Even if a prompt skill passes content scanning, it still goes through the sanitization pipeline. These controls reduce specific prompt-content risks, but they do not establish a process sandbox or prove that the skill’s instructions are trustworthy.
Configuration
Content scanning is enabled by default. You can adjust its behavior in your configuration file:installVetting block tunes the install gate’s bounds only. There is no switch to turn the install gate off.
How Scanning Fits into the Security Stack
Prompt-skill scanning is one layer in the Comis defense-in-depth security model:- Install vetting inspects every file in a skill bundle, plus its structure and manifest, before anything is written to disk (this page)
- Content scanning flags known patterns before a prompt skill loads (this page)
- Sanitization removes selected hidden or obfuscated content from prompt-skill bodies (this page)
- Agent tool policy filters registered tools by the configured profile and allow/deny rules (Tool Policy)
- Tool-specific validation constrains the particular operation being requested
- Exec sandboxing, when a supported provider is active, confines only child processes launched through ordinary
exec; MCP servers, browsers, and in-process tools are outside it (Sandbox) - Completed-response scanning can catch secret-shaped content before non-streaming delivery; already-emitted streaming deltas cannot be retracted
Sandbox
Where process isolation applies, and where it does not
Defense in Depth
All security layers explained
Manifest Reference
Declaring skill permissions
Prompt Skills
Creating custom prompt skills
