Cursor, Plugin
contentforge
An open-source editorial production system that researches, verifies, drafts, and delivers publication-ready long-form content with human review and provenance built in.
Compatibility: Portable across standard formats.
Grade D
Two or more Medium findings, or a High finding. Only try it in a sandbox.
Not a guarantee. A hygiene check of the source at the commit shown, not a security audit.
Rescanned at commit 8eb6b724ee88, unchanged since the check below.
NETWORK_HOST_FROM_INPUT SECRETS_PATH_CREDENTIAL
Why this grade
- NETWORK_HOST_FROM_INPUT Medium
A file takes a URL or endpoint as input and has no fixed host list.
scripts/harvest-brand-pages.py, line 207
def fetch(url: str, timeout: float) -> tuple[int, str]: - SECRETS_PATH_CREDENTIAL Medium
Mentions a credential store path (~/.ssh, id_rsa, .npmrc, .aws/credentials, credentials.json, .netrc).
commands/brand-setup.md, line 244
"credentials_path": "~/.claude-marketing/google-credentials.json",
Any High, or two or more Medium findings, give D. One Medium gives C. Low findings or a security Note give B. Each code names a finding behind the letter.
Grades are a hygiene check of the source at the commit shown, on the date checked, not a security audit or a guarantee. The free directory grades are automated. Before release, a PlugVet engineer reviews every paid report and any grade we hold back, including all F grades, against the source code and the evidence we quote.
What was checked
Plain notes from the hygiene checks.
Permissions
Concern
can delete files.
PERMISSION_DELETE_FILES
scripts/_common.py, line 382
subprocess.check_call(
scripts/backend-migrator.py, line 240
shutil.rmtree(tmp_dir, ignore_errors=True)
scripts/backend-migrator.py, line 252
shutil.rmtree(d, ignore_errors=True)
Show more
scripts/checkpoint-manager.py, line 568
shutil.rmtree(rd)
scripts/run-audit.py, line 503
proc = subprocess.run(
Install and update
Pass
No install-time script found, and dependencies are pinned or absent.
Network
Concern
can reach a host that is not written as a fixed address. accepts a host from input, with no fixed list in this file.
NETWORK_HOST_FROM_INPUT NETWORK_NO_FIXED_HOST
scripts/harvest-brand-pages.py, line 207
def fetch(url: str, timeout: float) -> tuple[int, str]:
scripts/harvest-brand-pages.py, line 350
status, robots_txt = fetch(root + "/robots.txt", args.timeout)
scripts/harvest-brand-pages.py, line 366
s_status, s_body = fetch(sm, args.timeout)
Show more
scripts/harvest-brand-pages.py, line 372
c_status, c_body = fetch(child, args.timeout)
scripts/harvest-brand-pages.py, line 381
h_status, h_body = fetch(root + "/", args.timeout)
scripts/harvest-brand-pages.py, line 394
p_status, p_body = fetch(u, args.timeout)
scripts/refresh_models.py, line 49
with urllib.request.urlopen(req, timeout=timeout) as resp:
research/2026-08-17-link-graph-and-claim-library-spec.md, line 66
existing `fetch()` - batched, polite, capped.
Secrets
Concern
reads a credential or environment file.
SECRETS_ENV_READ SECRETS_PATH_CREDENTIAL
commands/brand-setup.md, line 244
"credentials_path": "~/.claude-marketing/google-credentials.json",
commands/brand-setup.md, line 260
"credentials_path": "~/.claude-marketing/google-credentials.json"
commands/brand-setup.md, line 264
"credentials_path": "~/.claude-marketing/google-credentials.json"
Show more
scripts/airtable-tracker.py, line 117
token = os.environ.get("AIRTABLE_TOKEN")
scripts/backend-migrator.py, line 50
return _common.marketing_home() / "google-credentials.json"
scripts/backend-migrator.py, line 153
token = os.environ.get("AIRTABLE_TOKEN")
scripts/backend-migrator.py, line 638
help="Path to Google credentials JSON (default: <marketing-home>/google-credentials.json)")
scripts/connector-status.py, line 179
"credentials": "~/.claude-marketing/google-credentials.json",
scripts/connector-status.py, line 195
"credentials": "~/.claude-marketing/google-credentials.json",
scripts/detect-drive-mcp.py, line 12
~/.claude-marketing/google-credentials.json. Required for fully
scripts/refresh_models.py, line 56
key = os.environ.get("ANTHROPIC_API_KEY")
scripts/refresh_models.py, line 69
key = os.environ.get("OPENAI_API_KEY")
scripts/refresh_models.py, line 82
key = os.environ.get("GEMINI_API_KEY")
scripts/setup.py, line 111
airtable_token = os.environ.get("AIRTABLE_TOKEN")
Agent instructions
Pass
No instruction to ignore earlier instructions or to hide a step.
Obfuscation
Note
a file was over the read cap and was not fully read.
OBFUSCATION_FILE_OVER_READ_CAP
CHANGELOG.md, line 1
# Changelog
Licence
Pass
A licence file is present (LICENSE).
Maintainer activity
Pass
The latest commit is within the last 365 days.
Note
Hygiene check of commit 8eb6b724ee88. can delete files. can reach a host that is not written as a fixed address. accepts a host from input, with no fixed list in this file. reads a credential or environment file. a file was over the read cap and was not fully read.
Date and source
Date checked:
github.com
Commit graded: 8eb6b724ee881eb80f0f9d3ce00835ffb840a3b0
This link goes to the original host. PlugVet does not host or check what you download from there, and installing it is your own decision and risk.