pmjc@0.1.0
CAUTION· not startedPublisher claims: "Enables AI agents to access connected services and accounts through one MCP/REST interface, run scheduled or event-triggered plain-English jobs, and securely manage notifications, approvals, credentials, and model routing." Observed in sandbox: no network, touches nothing outside the project, writes no memory.
Coverage
Not started: dependency install failed; the server itself was not observed.- Tested
- the dependency install step · every file read, file written and host contacted by what ran
- Not tested
- server startup · the tool list · tool behavior
What this means for the label: Caution here covers what ran. The server's tools were not exercised with a real credential, so nothing about their behavior is asserted; the credential summary below says what to do with that.
Before you give it your token
- It will ask for
PMJC_ADMIN_TOKENConfiguration, not credentials: COMPUTERNAME, PMJC_HOME, PMJC_MASTER_KEY, USERDOMAIN, USERNAME- Where it talks to
- no vendor host named in the codeAlso google.com, discord.com, openrouter.ai, messenger.com, playwright.dev, telegram.org, slack.com, ntfy.sh, home-assistant.io, openbsd.org, open-meteo.com, openstreetmap.org, overpass-api.de, wa.me, jokeapi.dev, microsoft.com, apple.com — not the publisher's domain; check what for before connecting.
- What the honeypot saw
- no credential files read · no network
- What we could not test
- server startup · the tool list · tool behavior
Connect it with a scoped credential, under the guard, and read the third-party hosts first. The code names google.com, discord.com, openrouter.ai, messenger.com, playwright.dev, telegram.org, slack.com, ntfy.sh, home-assistant.io, openbsd.org, open-meteo.com, openstreetmap.org, overpass-api.de, wa.me, jokeapi.dev, microsoft.com, apple.com as well as its own vendor. The guard injects PMJC_ADMIN_TOKEN only into requests to the host you bind (and its subdomains) and refuses the rest.
Never paste a credential into a chat, a ticket or a report, including ours. How the guard holds it.
Is [email protected] safe to install?
KillerSkills ran it in the KillerSkills honeypot sandbox (2 scenarios; not started: dependency install failed; the server itself was not observed) on 2026-11-08 and scored it 54/100 (Caution). It is not known to be malicious, but it has behaviour or code a security policy should decide on before install. Notable findings: Pipe-to-shell pattern; HTML comment carrying imperative instructions to the agent; Telegram Bot API URL. Summary: no network, touches nothing outside the project, writes no memory.
Behavior trace
Honeypot run · 0 s · 2 scenarios · 0 deviationsStatic findings
- If uv is missing, ask the user before installing it: Windows `powershell -c "irm https://astral.sh/uv/install.ps1 | iex"`, macOS/Linux `curl -LsSf https://astral.sh/uv/install.sh | sh`.Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.e.g. "Never message anyone without asking me first", "Weekday mornings I want short answers".Fix: Keep SKILL.md to visible, descriptive text. Remove comments and encoded text that address the agent.r = await self.http.post(f"https://api.telegram.org/bot{self.secret('bot_token')}/{method}", json=body)Fix: Replace encoded or assembled strings with plain literals and remove undeclared network calls.key: Optional[str] = typer.Option(None, help="private key file, e.g. ~/.ssh/id_ed25519"),Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.if machines is None: # first explicit machine: keep the ~/.ssh/config aliases that were implicitly availableFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.alias: Optional[str] = typer.Option(None, help="use an existing Host alias from ~/.ssh/config instead")):Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.key: Optional[str] = typer.Option(None, help="private key file, e.g. ~/.ssh/id_ed25519"),Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.parent = subprocess.Popen([sys.executable, "-c", PARENT], stdout=subprocess.PIPE, text=True)Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.r = subprocess.run(["schtasks", "/Create", "/TN", TASK, "/XML", str(f), "/F"], capture_output=True, text=True)Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out."nas": {"host": "192.0.2.10", "user": "admin", "port": 2222, "key": "~/.ssh/id_ed25519"},Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.subprocess.run(["systemctl", "--user", "daemon-reload"])Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# ---- tokens and kill switchFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.nas: {host: 192.0.2.10, user: admin, port: 22, key: ~/.ssh/id_ed25519}Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose."""Revoke one token, or all of them (the kill switch) when token_id is None."""Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.If `machines` isn't set, every Host alias in ~/.ssh/config is available (set `use_ssh_config: false` to stop that).Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.return subprocess.run(argv, capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=timeout,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.subprocess.run(["systemctl", "--user", "enable", "--now", "pmjc.service"])Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.SECRET_GLOBS = ["*secret*", "*token*", "*password*", "*.key", "*.pem", "*.pfx", "*.p12", "id_*", ".env", ".env.*",Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.builder: {alias: builder} # an existing Host alias from ~/.ssh/configFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.subprocess.run(["launchctl", "load", "-w", str(plist)])Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.nas: {host: 192.0.2.10, user: admin, port: 22, key: ~/.ssh/id_ed25519}Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.c = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(60)"])Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.await t.fn(word="x; rm -rf /") # pattern refuses itFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.subprocess.run(["schtasks", "/Run", "/TN", TASK], capture_output=True)Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.- If uv is missing, ask the user before installing it: Windows `powershell -c "irm https://astral.sh/uv/install.ps1 | iex"`, macOS/Linux `curl -LsSf https://astral.sh/uv/install.sh | sh`.Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.out = subprocess.run(["tasklist", "/FI", f"PID eq {pid}", "/NH"], capture_output=True, text=True).stdoutFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.out = subprocess.run([smi, "--query-gpu=utilization.gpu", "--format=csv,noheader,nounits"],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.r = subprocess.run(argv, timeout=timeout, capture_output=True, creationflags=flags)Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.return subprocess.run(argv, capture_output=True, text=True, encoding="utf-8", errors="replace",Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out."""Revoke one token, or --all (kill switch)."""Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.<h2>pmjc</h2> <p class="muted">Paste an admin token (from <code>pmjc setup</code> or <code>pmjc token create me --admin</code>). It stays in this browser tab onFix: Remove the text that addresses the agent rather than the reader; describe behavior, do not instruct."nas": {"host": "192.0.2.10", "user": "admin", "port": 2222, "key": "~/.ssh/id_ed25519"},Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.await t.fn(word="x; rm -rf /") # pattern refuses itFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.4. **Get the ids:** Discord Settings → Advanced → Developer Mode on. Then right-click (long-press on a phone) yourself → Copy User ID, and each channel → Copy Channel ID.Fix: Keep SKILL.md to visible, descriptive text. Remove comments and encoded text that address the agent.4. **Get the ids:** Discord Settings → Advanced → Developer Mode on. Then right-click (long-press on a phone) yourself → Copy User ID, and each channel → Copy Channel ID.Fix: Remove the text that addresses the agent rather than the reader; describe behavior, do not instruct.Cost to the agent
Tokens estimated at four characters each. The tool list is re-read by the agent on every turn, so it is the number to compare between servers that do the same job: ranked across the index.
Known vulnerabilities
Vulnerability advisories (OSV) cover npm and PyPI packages; this registry has no advisory database.
What would make this Verified
26 points to 80 · weights: behavior 45%, static 25%, prompt 15%, publisher 15%- Asks the agent to act silently or skip confirmation≈ +8 on the totalRemove "do not tell the user", "without asking", "disable safety" and similar. An agent skill should never ask to be invisible.
- Unclaimed publisher≈ +8 on the totalClaim fwogg3r: a verified publisher gets +50 on publisher trust. It is free and usually instant with GitHub sign-in.
- Hidden instructions≈ +6 on the totalRemove HTML comments, zero-width characters and white-on-white text that carry instructions. Everything the agent is meant to read should be visible to the person reading the file.
- Pipe-to-shell pattern≈ +4 on the totalBuild commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.
- Telegram Bot API URL≈ +4 on the totalReplace encoded or assembled strings with plain literals and remove undeclared network calls.
- Access to sensitive file paths≈ +4 on the totalStop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.