T06 · System Persistence
- Location
scripts/setup.sh:24- Finding
Persistent systemd User Service Installation
- Content
View full analysis
"$SERVICE_FILE" <- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill does what it says, but it starts unauthenticated file-sharing services that are broadly reachable and can run beyond the current session.
Install only if you want a no-auth file drop and file browser on a trusted network. Before running it, prefer binding to a specific trusted interface or localhost, add firewall rules, avoid placing sensitive files in the shared directory, monitor disk usage, and disable/remove the systemd services when finished.
scripts/setup.sh:24Persistent systemd User Service Installation
scripts/upload-server.py:15Unauthenticated Network File Disclosure and Arbitrary File Overwrite
scripts/upload-server.py:64Unbounded File Upload Enables Disk and Service Exhaustion
scripts/server.js:69Unvalidated Host Header Reflected into Directory-Listing HTML
Upload new files via http://${hostname}:18802/
The declared description says the skill provides two components: a static file server for serving files and an upload server for users to send files back to the agent. The supplied code only creates a single HTTP server that accepts GET requests, lists files in MEDIA_ROOT, and serves existing files. It explicitly rejects non-GET methods, so it does not support file uploads. Although the generated HTML mentions uploads via port 18802, that functionality is not present in the code chunk. Therefore the code materially underdelivers relative to the declared bidirectional LAN file sharing purpose.
The declared description promises two core capabilities: a static file server for serving files and a separate upload server with a web UI for receiving files from users. The supplied code chunk only sets up one Node.js service on a single port (default 18801) and advertises dropping files into a local directory to share links, which aligns with one-way file serving. There is no setup or indication of a second server, port 18802, upload handling, or drag-and-drop UI. The systemd persistence is an additional implementation behavior not reflected in the description, though the main issue is that the actual behavior shown is materially narrower than the declared bidirectional LAN file-sharing purpose.
The description covers a two-part system: a static file server for serving files and an upload server for receiving them, implying a bidirectional LAN file-sharing capability. The provided code chunk only implements the upload server component on port 18802. It does serve a simple upload UI and saves uploaded files locally, and it references a media server on port 18801 by constructing download/view URLs, but it does not itself provide file-serving behavior. Therefore, the code only partially matches the declared purpose and omits a core declared capability from this chunk. There are no clear unrelated or malicious extra capabilities beyond permissive CORS and local file saving, but the supplied code does not fully represent the declared bidirectional system.
Without declared permissions the skill's intent is opaque and cannot be validated.
The skill explicitly instructs enabling systemd user services for auto-start, creating persistence beyond the current session. Persistence increases risk because network-facing file-sharing services will continue running after the initial task, potentially exposing unauthenticated upload/download endpoints to the LAN without ongoing user awareness.
Enable auto-start (run once from your login session):
systemctl --user enable media-server.service upload-server.service
Start/stop/restart/check status:
This section documents that systemd services run under the user account, confirming persistent background execution of a network service. In context, the skill already warns about lack of authentication and LAN exposure, so persistence materially raises the window of attack by keeping those endpoints available continuously.
- **Firewall recommended** — Even on LAN, consider blocking external interfaces (WAN) using a host firewall (`ufw`, `iptables`). Allow only your LAN subnet to ports 18801/18802.
- **Directory listing** — The media server root (`:18801/`) shows all filenames. This may leak information. If privacy is needed, disable directory listing by modifying `server.js` or block access via firewall.
- **Content Security** — The upload page uses inline JavaScript (CSP relaxed). This is acceptable for a local-only service, but be aware.
- **Systemd services** — If you enable systemd services, they run under your user account. Ensure your user account is secure. Consider using a dedicated low-privilege user for production.
### Best Practice: Manual Start for Testing
Referencing systemctl --user enable again reinforces a design that persists the service outside the immediate session. For an unauthenticated LAN file server/upload service, persistent availability increases the chance of unauthorized access, accidental data exposure, or abuse by any host that can reach the open ports.
The upload page is served from the same port as the upload endpoint (18802), so cross-origin issues shouldn't occur. Ensure you're accessing `http://<host>:18802/` and not the old media-server copy.
### Systemd user bus not available
Run `systemctl --user enable ...` from your normal login shell (not a cron or SSH non-interactive session without DBUS_SESSION_BUS_ADDRESS set). The `install-all.sh` script will start servers manually in any case.
---
The installer creates systemd services that explicitly bind both servers to 0.0.0.0, exposing file hosting and file upload functionality to every network interface by default. In the context of a LAN file-sharing skill, this is especially risky because it enables unauthenticated network access to shared files and upload endpoints unless the user independently understands and restricts the network boundary.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
# Reload systemd user daemon (if available)
if command -v systemctl &> /dev/null; then
systemctl --user daemon-reload 2>/dev/null || echo "⚠️ Could not reload systemd user daemon (no user bus?). Services will be available at next login."
echo "✅ Systemd service files created"
else
echo "⚠️ systemctl not found — services not enabled. Start servers manually."
fi
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
systemctl --user daemon-reload 2>/dev/null || echo "⚠️ Could not reload systemd user daemon (no user bus?). Services will be available at next login."
echo "✅ Systemd service files created"
else
echo "⚠️ systemctl not found — services not enabled. Start servers manually."
fi
# Start services now
The service binds to 0.0.0.0 by default and serves files from a user-controlled directory, making the contents reachable by any host on the local network. In the context of an agent skill meant for file exchange, this increases exposure because users may assume 'LAN-only' is inherently safe, while anyone on the same network can browse and fetch files without authentication.
The server will serve any file located under MEDIA_ROOT, including HTML, JavaScript, JSON, ZIP, and other non-media content, despite being described as a media-sharing service. In this skill context, MEDIA_ROOT defaults to a user directory under HOME and the service is exposed over the LAN, so sensitive or unintended files placed there can be disclosed to anyone who can reach the port.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
# Enable and start
systemctl --user daemon-reload
systemctl --user enable media-server.service
systemctl --user restart media-server.service
echo ""
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
# Enable and start
systemctl --user daemon-reload
systemctl --user enable media-server.service
systemctl --user restart media-server.service
echo ""
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
if ! loginctl show-user "$(whoami)" 2>/dev/null | grep -q 'Linger=yes'; then
echo ""
echo "⚠️ User lingering not enabled. Run this to survive reboots:"
echo " sudo loginctl enable-linger $(whoami)"
fi
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
dest_path = MEDIA_ROOT / filename
try:
with open(dest_path, 'wb') as f:
# Read in chunks to handle large files
while True:
chunk = file_item.file.read(8192)
The installer creates directories, writes systemd unit files, and stores PID/log files under user-accessible paths as part of installation. While some actions are echoed, there is no explicit warning or confirmation that persistent user service configuration files will be created and potentially auto-started later.
The inline comment says the code blocks null bytes and double-encoded traversal, but the implementation merely rejects a NUL byte or the substring '..' after a single decodeURIComponent call. This documentation overstates what the code actually detects and could mislead maintainers about the strength of the path validation.
This script creates and overwrites a persistent systemd user service file under ~/.config/systemd/user, which modifies the user's environment beyond the current shell session. Although it logs the created path afterward, there is no warning or confirmation before performing the write or before enabling the persistent service.
The script reloads systemd, enables the service, and restarts it immediately, causing a persistent background process to be installed and started. While the script announces success afterward, it does not clearly disclose beforehand that it will register and launch a long-running user service.
No suspicious patterns detected.