Back to skill

Security audit

formatferry-markdown

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a legitimate document-to-Markdown converter, but it installs and runs an unpinned global npm executable against potentially sensitive files.

Review before installing. Use this only if you trust the npm package source, prefer a pinned reviewed version, avoid global installs where possible, use --offline for private local conversion, and do not use --url for sensitive, internal, or confidential content unless server-side processing is acceptable.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:18
Finding
Unpinned Global Installation of an Unaudited npm Executable## Vulnerability Details **File Locations**: - `SKILL.md:18-20` - `SKILL.md:34-38` - `SKILL.md:132` - `README.md:7` - `scripts/convert-to-md.sh:45-47` **Vulnerability Type**: Unpinned third-party executable dependency **Risk Level**: Medium ### Vulnerable Code `SKILL.md:18-20`: ```yaml install: - kind: node package: formatferry bins: [formatferry] ``` `SKILL.md:34-38`: ```markdown - **Node.js 18+** and **npm** must be installed - Install the CLI globally: ```bash npm install -g formatferry ``` ``` `SKILL.md:132`: ```markdown | `formatferry: command not found` | Install via `npm install -g formatferry` | ``` `README.md:7`: ```bash npm install -g formatferry ``` `scripts/convert-to-md.sh:45-47`: ```bash if ! command -v formatferry &> /dev/null; then echo "Error: formatferry not found. Install with: npm install -g formatferry" &>&2 exit 1 fi ``` ### Technical Analysis The Skill directs users or the hosting framework to install `formatferry` from npm without specifying an exact version or integrity value. The package is installed globally and subsequently executed against potentially sensitive local documents. The implementation of the npm dependency is not included in the audited project. Consequently, this audit cannot verify its lifecycle scripts, local file access, environment-variable handling, credential storage, or network behavior. An unpinned installation resolves whichever package release the registry currently serves, allowing the executable code to change after this Skill has been reviewed. Global npm installation can also execute package lifecycle scripts with the installing user's privileges. At runtime, the installed program may inherit access to local files and environment variables, including the documented `FORMATFERRY_API_KEY` and `FORMATFERRY_LICENSE_KEY`. There is also ...[truncated 2301 chars]
Remediation
## Remediation Suggestions 1. Pin the dependency to an exact reviewed version, such as: ```bash npm install --save-exact formatferry@1.0.27 ``` The selected version must match the version actually reviewed and documented. 2. Avoid global installation. Declare the package as a project-local dependency and invoke the locked executable from `node_modules/.bin`. 3. Commit a lockfile containing npm integrity hashes and require deterministic frozen-lockfile installation, for example with `npm ci`. 4. Record and verify the expected package tarball integrity digest before installation. 5. Audit the exact dependency source revision, including: - npm lifecycle scripts; - outbound network destinations; - API and license-key storage; - local file access; - update mechanisms; - transitive dependencies. 6. Disable npm lifecycle scripts with `--ignore-scripts` if the reviewed package does not require them. If scripts are necessary, document and audit each script explicitly. 7. Run conversion in a restricted environment with access only to the required input and output paths. Remove unrelated secrets from the child process environment. 8. Keep local conversion offline by default. Require explicit user confirmation before enabling URL extraction or entitlement-related network access. 9. Align `SKILL.md`, `README.md`, and `references/cli-reference.md` on one verified CLI version and update them together when that version changes.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill is framed as local-first and emphasizes that file content never leaves the machine, but it also documents a `--url` mode that performs server-side fetching/processing and a possible license-validation network ping. This mismatch can mislead users or agents into invoking the tool in contexts that assume no network egress, causing unintended data disclosure or policy violations when remote URLs or entitlement checks are used.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The README claims the tool is 'local-first' and emphasizes that file content never leaves the machine, but it also documents a `--url` mode that requires an API key and therefore introduces remote network processing. This discrepancy can mislead users and downstream integrators about the trust boundary, causing them to use the tool in environments where outbound requests or external content handling are prohibited.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
Documenting a network/API-backed `--url` capability in a skill presented as an in-process local converter expands the attack surface beyond the stated purpose. Users may assume the package is safe for offline or restricted environments, but the URL feature can trigger outbound connections, external content ingestion, and possible data-handling or SSRF-like risk depending on implementation.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The CLI reference contradicts the 'local-first' positioning by documenting `--url` fetching and license-server entitlement checks, which introduce network interaction and possible data disclosure beyond purely local processing. Even if local file conversion remains in-process, users may be misled about the product’s trust boundary and unintentionally expose URLs, metadata, or document content to remote services.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The `--url` feature fetches arbitrary remote content and requires an API key, but the reference does not warn that remote retrieval or downstream processing may send user-supplied URLs or extracted content to an external service. In a tool marketed as local-first, this omission increases the risk that users will unknowingly transmit sensitive targets, internal URLs, or proprietary content.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
Documented support for storing API keys and license keys expands the attack surface for a tool whose stated purpose is document conversion, especially when the security model for credential storage is not described. This can lead to unnecessary secret handling, local credential exposure, and user confusion about why a converter needs persistent authentication capabilities.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The manifest emphasizes local, in-process conversion where file content never leaves the machine for local files, which sets an expectation of local document handling. This script expands the skill's behavior by accepting a `--url` input and forwarding it to `formatferry`, enabling remote resource fetching beyond the locally scoped conversion described.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
A document converter for local files is expected to read provided local content or stdin, not initiate retrieval of remote resources. Supporting `--url` introduces external access behavior that is outside the clearly stated local-first scope in the manifest.

Static analysis

No suspicious patterns detected.