Skip to main content
Comis inspects skill content at two points: an install-time vetting gate that runs before any file is written to disk, and a load-time scan each time a prompt skill is read into context. Both use the same six categories of dangerous patterns. This is a heuristic content filter, not malware analysis, code isolation, or a guarantee that an untrusted skill is safe.

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.
The two differ in scope and in what an operator may change:
contentScanning.enabled: false relaxes only the load-time scan. It does not disable the install gate — a deployment cannot configure its way into writing unvetted skill files.

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 — the SKILL.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.
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
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:
  • printenv commands
  • Reading /proc/*/environ
  • env | grep patterns that filter for specific secrets
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
Severity: mixed (WARN for piped downloads, CRITICAL for reverse shells)Detects attempts to send your data to external servers without authorization.Examples caught:
  • curl | sh patterns that download and execute remote code (WARN)
  • wget -O- | bash download-and-run chains (WARN)
  • Reverse shell patterns that open a connection back to an attacker (CRITICAL)
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 | bash decode-and-execute patterns (CRITICAL)
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.md at 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.md is still caught.
  • Bound breaches — too many files, too large a bundle, or too large a single file. See Configuration.
Logged as warnings, but installed:
  • 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.md rather than SKILL.md).
A bundle may ship a .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.
The permissions and allowedTools fields in SKILL.md are currently parsed as manifest metadata; they are not an enforced per-skill runtime authorization boundary. Configure the agent’s toolPolicy and the underlying tool-specific controls for actual enforcement. The default agent tool-policy profile is full, so narrow it before exposing an agent to untrusted content.

Configuration

Content scanning is enabled by default. You can adjust its behavior in your configuration file:
The installVetting block tunes the install gate’s bounds only. There is no switch to turn the install gate off.
Setting contentScanning.enabled to false or blockOnCritical to false removes the load-time layer. Only do this if you fully trust every skill that Comis will load, and you understand the risks. Neither setting affects the install gate.

How Scanning Fits into the Security Stack

Prompt-skill scanning is one layer in the Comis defense-in-depth security model:
  1. Install vetting inspects every file in a skill bundle, plus its structure and manifest, before anything is written to disk (this page)
  2. Content scanning flags known patterns before a prompt skill loads (this page)
  3. Sanitization removes selected hidden or obfuscated content from prompt-skill bodies (this page)
  4. Agent tool policy filters registered tools by the configured profile and allow/deny rules (Tool Policy)
  5. Tool-specific validation constrains the particular operation being requested
  6. 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)
  7. Completed-response scanning can catch secret-shaped content before non-streaming delivery; already-emitted streaming deltas cannot be retracted
These layers have different scopes. Verify the controls that apply to the exact skill, tool, host, and delivery mode you deploy.

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