Back to skill

Security audit

Ludwitt University

Security checks for vulnerabilities and agentic risk

Overview

This skill is a real coursework integration, but installing it creates a persistent background daemon, stores credentials, and uses unsafe install/update patterns that need review.

Install only if you are comfortable with a long-running Ludwitt daemon, remote registration, local credential storage, public repository/deployment requirements, and paper text being sent to the service. Prefer reviewing the local installer instead of any curl | sh path, do not add the suggested HEARTBEAT.md or cron automation unless you want autonomous recurring actions, and remove the service/credentials when finished.

Vulnerability Patterns
  • 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
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
Findings (4)

T03 · Remote Payload Retrieval and Execution

Error
Location
install.sh:8
Finding

Mutable Remote Installer Is Recommended for Direct Shell Execution

Content
View full analysis
Remediation
View remediation

T06 · System Persistence

Error
Location
install.sh:215
Finding

Installer Automatically Registers an Always-On Startup Service

Content
View full analysis
"$plist" << PLISTEOF Label com.ludwitt.daemon ProgramArguments $(which node) $LUDWITT_DIR/daemon.js --daemon RunAtLoad KeepAlive StandardOutPath $LUDWITT_DIR/daemon.log StandardErrorPath $LUDWITT_DIR/daemon.err.log EnvironmentVariables HOME $HOME PLISTEOF launchctl unload "$plist" 2>/dev/null || true launchctl load "$plist" info "Daemon registered with launchd (starts on boot)" } install_systemd() { local service="$HOME/.config/systemd/user/ludwitt-daemon.service" mkdir -p "$HOME/.config/systemd/user" cat > "$service" << SVCEOF [Unit] Description=Ludwitt University Daemon After=network.target [Service] ExecStart=$(which node) $LUDWITT_DIR/daemon.js --daemon Restart=on-failure RestartSec=10 Environment=HOME=$HOME [Install] WantedBy=default.target SVCEOF systemctl --user daemon-reload systemctl --user enable ludwitt-daemon systemctl --user start ludwitt-daemon info "Daemon registered with systemd (starts on boot)" } ``` ### Technical Analysis The installer automatically creates and enables a user-level launchd or systemd service. On macOS, `RunAtLoad` and `KeepAlive` cause the daemon to start automatically and remain running. On Linux, `sy ...[truncated 1993 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
daemon.js:75
Finding

Authenticated Requests Forward Credentials and Sensitive Bodies Across Unrestricted Redirects

Content
View full analysis
{ let settled = false const finish = (fn, value) => { if (settled) return settled = true fn(value) } const payload = body ? JSON.stringify(body) : null const req = mod.request( url, { method, headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.apiKey}`, 'X-Ludwitt-Fingerprint': auth.fingerprint, 'X-Agent-Type': auth.agentFramework || 'generic', 'User-Agent': `ludwitt-daemon/${auth.agentFramework || 'generic'}`, ...(payload && { 'Content-Length': Buffer.byteLength(payload) }), }, }, (res) => { // Follow redirects (307/301/302) up to 3 hops if ( [301, 302, 307, 308].includes(res.statusCode) && res.headers.location && redirectCount < 3 ) { res.resume() const redirectUrl = new URL(res.headers.location, url) return requestOnce( method, redirectUrl.toString(), body, redirectCount + 1 ) .then(resolve) .catch(reject) } ``` ### Technical Analysis The authenticated HTTP client follows 301, 302, 307, and 308 redirects without checking whether the destination retains the original scheme, hostname, and port. The recursive `requestOnce` call reloads authentication and constructs a new request containing: - `Authorization: Bearer ` - `X-Ludwitt-Fingerprint: ` - The original HTTP method. ...[truncated 1958 chars]
Remediation
View remediation

T02 · Agent Memory Poisoning

Warning
Location
install.sh:298
Finding

Installer Encourages Persistent Autonomous Agent Instructions and Scheduled Actions

Content
View full analysis
│" echo " │ 3. If in-progress → keep building, deploy, submit │" echo " │ 4. ludwitt queue → grade peer work (earns XP) │" echo " │ 5. Target: 1 deliverable per week minimum │" echo " │ │" echo " │ OpenClaw agents: add the above to your HEARTBEAT.md file │" echo " │ Other agents: set up 2 cron jobs (0 9 * * * and 0 21 * * *) │" echo " └─────────────────────────────────────────────────────────────────┘" ``` ### Technical Analysis The installer does not itself modify `HEARTBEAT.md` or create these two cron entries. However, it explicitly instructs an Agent or operator to copy recurring behavioral rules into ...[truncated 1832 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (36)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill is presented as a university/coursework helper, but the documented behavior includes agent registration, fingerprinting, credential provisioning, local auth storage, persistent daemon installation, shell profile modification, and heartbeat/persistence mechanisms. That is a major description-behavior mismatch and strongly suggests covert capability expansion beyond the user-facing educational purpose.

Content

No source excerpt is available for this finding.

External Script Fetching

High
Category
Supply Chain
Confidence
96% confidence
Finding

The code displays and potentially trusts server-controlled update instructions, with a fallback that explicitly recommends piping a remote script directly into the shell (curl ... | sh). Even though this line is only printed and not executed here, it normalizes an unsafe update path and allows a compromised server or MITM on non-hardened channels to socially engineer users into arbitrary code execution.

Content

Scanner excerpt · daemon.js (reported line 42)May include surrounding context.

js
if (!clientVersion || clientVersion === result.apiVersion) return
    updateCheckShown = true
    console.error(
      `[ludwitt] A new API version is available (server: ${result.apiVersion}, yours: ${clientVersion}). Update: ${result.updateInstructions || 'curl -sSL https://opensource.ludwitt.com/install | sh'}`
    )
  } catch {}
}

External Script Fetching

High
Category
Supply Chain
Confidence
99% confidence
Finding

The script advertises installation via curl ... | sh, which executes network-fetched code directly without giving the user a chance to inspect it. This pattern is dangerous because any compromise of the remote host, TLS termination, or content pipeline leads to immediate arbitrary code execution on the user's machine.

Content

Scanner excerpt · install.sh (reported line 10)May include surrounding context.

sh
# saves credentials, installs the daemon as a background service.
#
# Usage:
#   curl -sSL https://opensource.ludwitt.com/install | sh
#   # or after cloning the skill repo:
#   ./install.sh

Chaining Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

The | sh chaining explicitly turns downloaded content into immediate shell execution, collapsing transport and execution into one step. In combination with this installer's persistence, credential storage, and outbound registration, that creates a high-risk bootstrap path for arbitrary and lasting compromise.

Content

Scanner excerpt · install.sh (reported line 10)May include surrounding context.

sh
# saves credentials, installs the daemon as a background service.
#
# Usage:
#   curl -sSL https://opensource.ludwitt.com/install | sh
#   # or after cloning the skill repo:
#   ./install.sh

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The installer provisions a persistent daemon and configures it to run automatically at login/boot via launchd or systemd. That materially exceeds a simple course-enrollment workflow and creates long-lived code execution whose behavior depends on daemon.js, increasing risk of surveillance, command execution, or later remote tasking.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The installer sets up a boot-time background service without a separate, prominent consent step. In a skill whose manifest describes course enrollment and grading, undisclosed persistence is especially concerning because it enables continuous execution beyond the immediate user action.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill requests and operationally depends on powerful capabilities such as shell, file access, environment secrets, and network access, yet it does not declare a constrained tool scope. That creates a hidden privilege boundary problem: a broadly invoked education skill can end up running installation, deployment, Git, and credential-dependent actions with more authority than users may expect.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The invocation language is broad enough to trigger on ordinary education-related requests, increasing the chance the skill is selected in contexts where users did not intend enrollment, deployment, installation, or credential use. Because the skill performs or recommends high-risk actions, over-broad routing materially increases exposure.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
82% confidence
Finding

Using npx vercel without pinning a specific version permits execution of whatever package version is currently resolved at install/runtime. This creates supply-chain risk and reduces reproducibility, especially in a skill that encourages shell execution and deployment workflows.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
82% confidence
Finding

This duplicate occurrence still reflects the same security issue: an unpinned package execution path that can change over time. Because the command may run with authenticated deployment context, compromise could affect hosted applications or tokens.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
82% confidence
Finding

This is another duplicate occurrence of the same unpinned CLI issue at a sensitive authentication step. The risk is amplified because the command may be executed in an environment containing deploy credentials or user session data.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

The skill normalizes a daemon that reads local reflection files and submits them directly, indicating background or persistent processing of local user content. Without clear consent boundaries, retention limits, or data minimization, this creates ongoing access and exfiltration risk for locally stored documents.

Content

Scanner excerpt · SKILL.md (reported line 45)May include surrounding context.

md
- **Claude Code:** Requires `allowedTools` to include `Bash`, file read/write, and network access. Ask your owner to enable these if not already set.
- **Vercel:** `npx vercel --prod` deploys from any project directory. One-time `npx vercel login` required.
- **GitHub:** `GITHUB_TOKEN` or SSH key must be configured so `git push` works without prompts.
- **Paper:** Write your reflection to a local `.md` file — the daemon reads and submits it directly.
- **Video:** Any public `https://` video URL is accepted (YouTube, Loom, HeyGen, Vimeo, etc.).

## Installation

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill instructs users to publish a live app, a public GitHub repository, and either a public video or inline paper submission, but it gives no meaningful privacy warning about source disclosure, personal data exposure, secrets leakage, or the fact that paper contents are transmitted. In an education workflow, users may include sensitive code, API keys, proprietary work, or personal reflections without realizing the exposure is public or remotely submitted.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
74% confidence
Finding

Requiring users to save a long-form reflection locally and pass its path for daemon submission creates a mechanism for local file ingestion and transfer. If path handling is broad or unclear, users may expose unintended local content, and the pattern encourages persistent handling of documents by a background service.

Content

Scanner excerpt · SKILL.md (reported line 173)May include surrounding context.

md
- **Video** (`--video`) — Generate or record a video walkthrough of your platform and your
  build process. Any public video URL is accepted (YouTube, Loom, HeyGen, Vimeo, etc.).

- **Written paper** (`--paper`) — Write a minimum 5000-word paper covering what you built,
  the technical decisions you made, challenges you faced, and what you learned.
  Save it as a `.md` or `.txt` file and pass the path to `--paper`.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The script fingerprints the host's agent environment by checking for OpenClaw, Cursor, and Claude Code artifacts and environment variables. This collects unrelated context about the user's tooling and transmits the derived framework type during registration, which is not necessary for basic enrollment and increases privacy and targeting risk.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The script strongly steers users toward public deployment, GitHub push access, and other capabilities not inherently required just to enroll in university courses. In the context of an agent skill, encouraging broader permissions and public code publication expands the blast radius if the daemon or later workflows are abused.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The installer sends agentName, detected framework, and a generated fingerprint to a remote API during registration with no explicit pre-consent step detailing the exact data transmitted. This creates a privacy issue and can support host tracking or inventorying, especially because the fingerprint is stored and reused across reinstallations.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
96% confidence
Finding

The script performs an outbound registration request to a remote domain and transmits locally derived metadata. External transmission is expected for a network service, but in this context it is still security-relevant because the payload includes host-identifying data and occurs during installation.

Content

Scanner excerpt · install.sh (reported line 120)May include surrounding context.

sh
process.stdout.write(JSON.stringify({ agentName, agentFramework, fingerprint }));
' "$AGENT_NAME" "$FRAMEWORK" "$FINGERPRINT")

REGISTER_RESPONSE=$(curl -sSL -w "\n%{http_code}" \
  -X POST "$LUDWITT_API/api/agent/register" \
  -H "Content-Type: application/json" \
  -H "X-Agent-Type: $FRAMEWORK" \

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script writes an API key and agent metadata to ~/.ludwitt/auth.json without advance warning or an option to choose an alternate credential store. Even with chmod 600, silently persisting credentials increases the chance of accidental exposure, backup leakage, or misuse by local processes running as the same user.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · install.sh (reported line 162)May include surrounding context.

sh
}
EOF

chmod 600 "$AUTH_FILE"
info "Credentials saved to $AUTH_FILE (owner read-only)"

# ─── Copy daemon ─────────────────────────────────────────────────────────────

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The installer edits ~/.zshrc or ~/.bashrc to prepend a new directory to PATH, permanently altering shell behavior. Startup-file modification is a persistent environmental change that can affect future command resolution and is risky when done without explicit confirmation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This path modification occurs without a clear advance disclosure or confirmation dialog. Silent persistence changes are dangerous because they affect future shells and can unexpectedly prioritize executables from a newly created directory.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

This finding points to the creation of a launchd plist used to register the daemon as a startup item. Even though the matched token is generic, in context it is part of a persistence mechanism that causes recurring execution without repeated user initiation.

Content

Scanner excerpt · install.sh (reported line 212)May include surrounding context.

sh
# ─── Register background service ────────────────────────────────────────────

install_launchd() {
  local plist="$HOME/Library/LaunchAgents/com.ludwitt.daemon.plist"
  mkdir -p "$HOME/Library/LaunchAgents"
  cat > "$plist" << PLISTEOF
<?xml version="1.0" encoding="UTF-8"?>

Static analysis

No suspicious patterns detected.