T03 · Remote Payload Retrieval and Execution
- Location
install.sh:8- Finding
Mutable Remote Installer Is Recommended for Direct Shell Execution
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
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.
install.sh:8Mutable Remote Installer Is Recommended for Direct Shell Execution
install.sh:215Installer Automatically Registers an Always-On Startup Service
daemon.js:75Authenticated Requests Forward Credentials and Sensitive Bodies Across Unrestricted Redirects
install.sh:298Installer Encourages Persistent Autonomous Agent Instructions and Scheduled Actions
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.
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.
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 {}
}
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.
# 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
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.
# 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
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.
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.
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.
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.
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.
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.
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.
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.
- **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
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.
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.
- **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`.
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.
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.
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.
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.
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.
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.
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" \
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.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
}
EOF
chmod 600 "$AUTH_FILE"
info "Credentials saved to $AUTH_FILE (owner read-only)"
# ─── Copy daemon ─────────────────────────────────────────────────────────────
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.
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.
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.
# ─── 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"?>
No suspicious patterns detected.