registry  /  openwriter  /  0.40.3

openwriter@0.40.3

The open-source writing surface for AI agents. Markdown-native editor with pending change review — your agent writes, you accept or reject.

AI Security Review

scanned 2h ago · by lpm-firewall-ai

LPM treats this as warn-only first-party agent extension lifecycle risk. No confirmed malicious install-time behavior was found. The package has real user-invoked risk: explicit Claude setup mutates a first-party agent control surface, and legacy sync routes can store PATs in git remotes plus use shell:true around git/gh arguments.

Static reason
One or more suspicious static signals were detected.; previous stored version diff introduced dangerous source
Trigger
user runs openwriter setup/install-skill or uses /api/sync/setup/openwriter GitHub sync
Impact
Claude Code gains OpenWriter MCP/skills; GitHub PAT may be written to .git/config and sync args may be shell-injection prone if attacker-controlled input reaches the local API
Mechanism
first-party MCP/skill setup plus vulnerable git sync command construction
Rationale
Source inspection shows no automatic install/import attack, credential harvesting, remote payload loading, or unconsented broad AI-agent hijack. However, explicit agent extension setup and the legacy GitHub sync implementation create real but user-invoked risk, so this should warn rather than block.
Evidence
package.jsondist/bin/pad.jsdist/server/install-skill.jsdist/server/git-sync.jsdist/server/sync-routes.jsdist/server/plugin-install.jsdist/plugins/github/dist/git-sync.jsskill/SKILL.mdskill/agents/openwriter-enrichment-minion.mdskill/agents/openwriter-sort-minion.md~/.claude.json~/.claude/skills/openwriter/SKILL.md~/.claude/agents/openwriter-enrichment-minion.md~/.claude/agents/openwriter-sort-minion.md~/.openwriter/config.json~/.openwriter/plugins/package.json.git/config
Network endpoints6
api.github.com/user/repospublish.openwriter.ioauthors-voice.comapi.x.com/2127.0.0.1:5050localhost:5050

Decision evidence

public snapshot
AI called this Suspicious at 86.0% confidence as Critical Vulnerability with low false-positive risk.
Evidence for warning
  • dist/server/install-skill.js explicitly writes ~/.claude.json and copies OpenWriter skills/agents when user runs setup.
  • dist/server/git-sync.js uses execFile(...,{shell:true}) and weak quoting for git/gh args from /api/sync/setup.
  • dist/server/git-sync.js embeds GitHub PATs in remote URLs for setupWithPat/connectExisting, writing them into .git/config.
  • dist/server/plugin-install.js runs npm install/uninstall for user-supplied plugin names, though names are regex-limited.
Evidence against
  • package.json has no preinstall/install/postinstall lifecycle hook; only prepublishOnly.
  • dist/bin/pad.js activates server/setup/plugin paths only when the user invokes the CLI.
  • dist/plugins/github/dist/git-sync.js uses safer execFile argv arrays and PAT env credential helper.
  • Packaged skill/agents are first-party OpenWriter workflow files with restricted OpenWriter MCP tools, not hidden exfiltration instructions.
  • Network endpoints are product-aligned: GitHub, OpenWriter publish, Author's Voice, X API, localhost.
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsFilesystemNetworkShellWebSocket
Supply chain
HighEntropyStringsMinifiedObfuscatedUrlStrings
ManifestNo manifest risk signals triggered.
scanned 87 file(s), 2.40 MB of source, external domains: 127.0.0.1, api.fxtwitter.com, api.github.com, api.x.com, authors-voice.com, developer.x.com, example.com, git-scm.com, github.com, prosemirror.net, publish.openwriter.io, purl.org, reactjs.org, registry.npmjs.org, twemoji.maxcdn.com, unavatar.io, www.idpf.org, www.w3.org, x.com

Source & flagged code

6 flagged · loading source
dist/plugins/github/dist/blog-tools.jsView file
6*/ L7: import { execFile } from 'child_process'; L8: import { existsSync, mkdirSync, readFileSync, copyFileSync, writeFileSync, readdirSync, statSync, rmSync } from 'fs';
High
Child Process

Package source references child process execution.

dist/plugins/github/dist/blog-tools.jsView on unpkg · L6
17// single literal argument and is NEVER interpreted by a shell. Do NOT add L18: // `shell: true` or hand-roll arg quoting here: that reintroduces OS command L19: // injection. If a future call genuinely needs shell features, whitelist-
High
Shell

Package source references shell execution.

dist/plugins/github/dist/blog-tools.jsView on unpkg · L17
dist/plugins/x-api/dist/server-bridge.jsView file
16let cached = null; L17: async function tryImport(base) { L18: const [state, helpers, draftjs] = await Promise.all([
Medium
Dynamic Require

Package source references dynamic require/import behavior.

dist/plugins/x-api/dist/server-bridge.jsView on unpkg · L16
dist/server/plugin-install.jsView file
34try { L35: execSync(`npm install --save ${packageName}`, { L36: cwd: PLUGINS_DIR,
High
Runtime Package Install

Package source invokes a package manager install command at runtime.

dist/server/plugin-install.jsView on unpkg · L34
dist/client/assets/source-serif-4-latin-wght-italic-D2yaqPoE.woff2View file
path = dist/client/assets/source-serif-4-latin-wght-italic-D2yaqPoE.woff2 kind = high_entropy_blob sizeBytes = 51516 magicHex = [redacted]
High
Ships High Entropy Blob

Package ships high-entropy non-source blobs.

dist/client/assets/source-serif-4-latin-wght-italic-D2yaqPoE.woff2View on unpkg
dist/plugins/github/dist/git-sync.jsView file
matchType = previous_version_dangerous_delta matchedPackage = openwriter@0.40.1 matchedIdentity = npm:b3BlbndyaXRlcg:0.40.1 similarity = 0.986 summary = stored previous version shares package body but lacks this dangerous source file
Critical
Previous Version Dangerous Delta

This package version adds a dangerous source file absent from the previous stored version; route for source-aware review.

dist/plugins/github/dist/git-sync.jsView on unpkg

Findings

1 Critical4 High4 Medium6 Low
CriticalPrevious Version Dangerous Deltadist/plugins/github/dist/git-sync.js
HighChild Processdist/plugins/github/dist/blog-tools.js
HighShelldist/plugins/github/dist/blog-tools.js
HighRuntime Package Installdist/server/plugin-install.js
HighShips High Entropy Blobdist/client/assets/source-serif-4-latin-wght-italic-D2yaqPoE.woff2
MediumDynamic Requiredist/plugins/x-api/dist/server-bridge.js
MediumNetwork
MediumEnvironment Vars
MediumStructural Risk Force Deep Review
LowNon Install Lifecycle Scripts
LowScripts Present
LowFilesystem
LowObfuscated
LowHigh Entropy Strings
LowUrl Strings