Back to skill

Security audit

raspberry-pi-camera-service

Security checks for vulnerabilities and agentic risk

Overview

This camera skill is purpose-aligned but needs Review because it installs a persistent network camera service that is unauthenticated, listens on all interfaces by default, and may run as root.

Install only on a trusted Raspberry Pi after changing the service to bind to localhost or a protected interface, adding authentication, avoiding public network exposure, using a dedicated non-root service account, and reviewing the system Python and dependency-install behavior. Treat captured photos and videos as sensitive retained data.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • 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
Findings (3)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/deploy/templates/.env.example.txt:4
Finding
Unauthenticated Camera Control and Recording Management Exposed on All Network Interfaces<![CDATA[ ## Vulnerability Details **File Location**: `scripts/deploy/templates/.env.example.txt:4`, `scripts/service.py:273-668`, `scripts/service.py:763-771` **Vulnerability Type**: Missing authentication and authorization on a network-exposed camera API **Risk Level**: High ### Vulnerable Code The deployment configuration exposes the service on every available network interface: ```ini # Service configuration HOST=0.0.0.0 PORT={{PORT}} LOG_LEVEL=INFO # Output directory OUTPUT_DIR={{WORKING_DIR}}/output ``` The application uses this value when starting Uvicorn: ```python if __name__ == "__main__": host: str = os.getenv("HOST", "0.0.0.0") port: int = int(os.getenv("PORT", "27793")) uvicorn.run( "service:app", host=host, port=port, reload=False, workers=1 # Single process so the lock remains effective ) ``` Security-sensitive endpoints are registered without any authentication or authorization dependency: ```python @app.post("/start", response_model=StartResponse) async def start_recording(request: StartRequest) -> StartResponse: ... @app.post("/stop/{session_id}", response_model=StopResponse) async def stop_recording( session_id: str, request: StopRequest, background_tasks: BackgroundTasks ) -> StopResponse: ... @app.post("/capture", response_model=CaptureResponse) async def capture_image(request: CaptureRequest) -> CaptureResponse: ... @app.get("/output/{filename}") async def get_video(filename: str) -> FileResponse: ... @app.delete("/output/{filename}") async def delete_file(filename: str) -> JSONResponse: ... @app.get("/outputs/") async def list_outputs( limit: int = Query(default=20, ge=1, le=100), offset: int = Query(default=0, ge=0) ) -> JSONResponse: ... ``` ### Technical Analysis Binding to `0.0.0.0` makes port 27793 reachable through every configured interface unless an external firewall blocks it. The FastAPI application does not requir ...[truncated 2619 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Change the deployment default to loopback-only access: ```ini HOST=127.0.0.1 ``` 2. Require authentication and authorization on every endpoint, including status, heartbeat, listing, download, and deletion endpoints. Use a FastAPI dependency that validates a securely generated bearer token or API key. 3. Do not return active session IDs, complete server filesystem paths, or other control credentials through an unauthenticated status endpoint. 4. For remote access, place the service behind a hardened TLS reverse proxy or use mutual TLS. Do not transmit camera data or credentials over plaintext HTTP. 5. Apply network restrictions: - Permit only explicitly trusted client addresses. - Block port 27793 on public and untrusted interfaces. - Consider access through a VPN or local Unix socket. 6. Separate read, capture, recording, and deletion permissions where multiple clients are supported. Destructive operations should require stronger authorization. 7. Add rate limiting, request auditing, and limits on recording duration and storage consumption. 8. Document the security boundary and warn operators not to expose the service directly to untrusted networks. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/deploy/install.sh:13
Finding
Persistent Network Service Runs as Root Due to Incorrect Service Account Selection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/deploy/install.sh:13-30`, `scripts/deploy/templates/service_template.service.txt:7-16` **Vulnerability Type**: Excessive operating-system privileges for a persistent network service **Risk Level**: High ### Vulnerable Code The installer derives the service identity from the effective user: ```bash # Configuration SERVICE_NAME="camera-service" SERVICE_USER=$(id -un) SERVICE_GROUP=$(id -gn) WORKING_DIR="/opt/camera-service" PYTHON_CMD="python3" PORT=27793 ``` The same installer explicitly requires root privileges: ```bash check_root() { if [ "$EUID" -ne 0 ]; then log_error "Please run this script with sudo" exit 1 fi } ``` The selected identity is inserted directly into the systemd service: ```ini [Service] Type=simple User={{SERVICE_USER}} Group={{SERVICE_GROUP}} WorkingDirectory={{WORKING_DIR}} Environment="PYTHONPATH={{WORKING_DIR}}" Environment="PATH={{WORKING_DIR}}/venv/bin:/usr/local/bin:/usr/bin:/bin" ExecStart={{WORKING_DIR}}/venv/bin/python {{WORKING_DIR}}/service.py ``` The service is then enabled persistently: ```bash start_service() { log_info "Reloading systemd..." systemctl daemon-reload log_info "Enabling service at boot..." systemctl enable "$SERVICE_NAME" log_info "Starting service..." systemctl start "$SERVICE_NAME" ... } ``` ### Technical Analysis The documented installation command runs the script through `sudo`. Inside that process, `id -un` and `id -gn` resolve the effective account and group, which are normally both `root`. The generated systemd unit therefore contains: ```ini User=root Group=root ``` Camera access does not require a permanently root-running application. A dedicated unprivileged service account with narrowly scoped access to the relevant video device is sufficient. The unit includes useful controls such as `NoNewPrivileges=true`, `PrivateTmp=true`, `ProtectSystem=strict`, and `ProtectHome=true ...[truncated 2564 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create a dedicated system account during installation: ```bash useradd \ --system \ --home-dir /opt/camera-service \ --shell /usr/sbin/nologin \ --user-group \ camera-service ``` 2. Grant only the camera access required by the deployment. For common Raspberry Pi configurations, add the dedicated account to the appropriate `video` group rather than running as root. 3. Set the service identity explicitly: ```ini User=camera-service Group=camera-service SupplementaryGroups=video ``` 4. Keep source code and the virtual environment root-owned and non-writable by the runtime account. Only the output directory should be writable by the service account. 5. Extend systemd hardening with controls appropriate to the target hardware, for example: ```ini CapabilityBoundingSet= AmbientCapabilities= DevicePolicy=closed DeviceAllow=/dev/video0 rw PrivateDevices=no ProtectKernelTunables=true ProtectKernelModules=true ProtectControlGroups=true RestrictSUIDSGID=true LockPersonality=true RestrictRealtime=true ``` Camera-specific device allowlists must be tested because CSI camera stacks may require multiple device nodes. 6. Consider adding `SystemCallFilter`, `RestrictAddressFamilies`, and `MemoryDenyWriteExecute` after compatibility testing with Python, FFmpeg, and Picamera2. 7. Resolve the original non-root invoking user explicitly only for client installation if necessary. Do not reuse the installer's effective root identity as the service identity. 8. Verify the generated unit during installation and fail if `SERVICE_USER` is `root`, unless an operator explicitly selects and acknowledges an exceptional root mode. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/requirements.txt:1
Finding
Unpinned Dependencies and System Python Modification During Privileged Installation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/requirements.txt:1-8`, `scripts/deploy/install.sh:122-132`, `scripts/deploy/install.sh:192-208` **Vulnerability Type**: Non-reproducible dependency installation and unsafe privileged package management **Risk Level**: Medium ### Vulnerable Code The dependency file specifies only lower bounds: ```text # Server dependencies fastapi>=0.104.0 uvicorn[standard]>=0.24.0 pydantic>=2.0.0 python-dotenv>=1.0.0 # Client dependencies requests>=2.31.0 ``` The root installer upgrades pip and resolves the latest matching packages from the configured package index: ```bash setup_venv() { log_info "Creating Python virtual environment..." cd "$WORKING_DIR" $PYTHON_CMD -m venv venv source venv/bin/activate log_info "Installing dependencies..." pip install --upgrade pip pip install -r requirements.txt chown -R $SERVICE_USER:$SERVICE_GROUP "$WORKING_DIR/venv" } ``` The client package is then installed into system Python while bypassing PEP 668 protections: ```bash # Install into system Python using --break-system-packages to bypass PEP 668 log_info "Installing camera-client package..." pip install "$pkg_dir" --quiet --break-system-packages # Clean up temporary directory rm -rf "$pkg_dir" ``` The generated client package also contains an unpinned dependency: ```toml [project] name = "camera-client" version = "1.0.0" description = "Raspberry Pi camera service client SDK" requires-python = ">=3.8" dependencies = [ "requests>=2.31.0", ] ``` ### Technical Analysis A lower-bound constraint allows any future release satisfying the version expression. Installation results can therefore change without any modification to the audited project. The selected dependency graph includes direct dependencies and additional transitive packages introduced by `uvicorn[standard]`, FastAPI, Requests, and their dependency chains. Python package installation may execute package build backends ...[truncated 2846 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Generate a reviewed lock file containing exact direct and transitive versions. 2. Record package hashes and enforce them during installation: ```bash python -m pip install --require-hashes -r requirements.lock ``` 3. Build and test updates through a controlled dependency-update process rather than resolving arbitrary future versions on production devices. 4. Pin the installer tooling or use the operating system's validated pip version. Do not automatically run an unconstrained `pip install --upgrade pip` in a privileged deployment script. 5. Install both the server and client into isolated virtual environments. Avoid `--break-system-packages`. 6. If system-wide client availability is required, use a distribution package, `pipx`, or an explicitly managed virtual environment with a wrapper command. 7. Run package resolution and installation under a non-root account where possible. Use root only for narrowly scoped ownership and service-registration operations. 8. Use an approved package index or internal mirror and enable dependency vulnerability scanning in the release process. 9. Verify downloaded artifacts against hashes generated in a trusted build environment, and document the expected dependency provenance. ]]>
Vulnerability Patterns
  • 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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (87)

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
Providing download, listing, and deletion endpoints for recorded files is a significant data-management capability not clearly captured by the manifest's simpler camera description. In a surveillance-adjacent context, these endpoints can expose or destroy sensitive recordings if users and defenders are unaware of them.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Providing download, listing, and deletion endpoints for recorded files is a significant data-management capability not clearly captured by the manifest's simpler camera description. In a surveillance-adjacent context, these endpoints can expose or destroy sensitive recordings if users and defenders are unaware of them.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Providing download, listing, and deletion endpoints for recorded files is a significant data-management capability not clearly captured by the manifest's simpler camera description. In a surveillance-adjacent context, these endpoints can expose or destroy sensitive recordings if users and defenders are unaware of them.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
Providing download, listing, and deletion endpoints for recorded files is a significant data-management capability not clearly captured by the manifest's simpler camera description. In a surveillance-adjacent context, these endpoints can expose or destroy sensitive recordings if users and defenders are unaware of them.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Providing download, listing, and deletion endpoints for recorded files is a significant data-management capability not clearly captured by the manifest's simpler camera description. In a surveillance-adjacent context, these endpoints can expose or destroy sensitive recordings if users and defenders are unaware of them.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
- `POST /stop/{session_id}`:停止录制并转换
- `PUT /heartbeat/{session_id}`:发送心跳续期会话
- `GET /videos/{filename}`:下载视频文件
- `DELETE /videos/{filename}`:删除视频文件
- `GET /videos/`:列出所有视频文件

#### 请求/响应模型
Confidence
90% confidence
Finding
This finding duplicates the same remote deletion surface: a DELETE endpoint taking a user-controlled filename parameter. In the context of a network-accessible camera service holding potentially sensitive recordings, unauthorized deletion or parameter abuse could cause loss of evidence, privacy-impacting tampering, or broader file deletion if validation is flawed.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
- `POST /stop/{session_id}`:停止录制并转换
- `PUT /heartbeat/{session_id}`:发送心跳续期会话
- `GET /videos/{filename}`:下载视频文件
- `DELETE /videos/{filename}`:删除视频文件
- `GET /videos/`:列出所有视频文件

#### 请求/响应模型
Confidence
90% confidence
Finding
This finding duplicates the same remote deletion surface: a DELETE endpoint taking a user-controlled filename parameter. In the context of a network-accessible camera service holding potentially sensitive recordings, unauthorized deletion or parameter abuse could cause loss of evidence, privacy-impacting tampering, or broader file deletion if validation is flawed.

Credential Access

High
Category
Privilege Escalation
Content
render_template \
        "$TEMPLATE_DIR/.env.example.txt" \
        "$WORKING_DIR/.env"

    chown $SERVICE_USER:$SERVICE_GROUP "$WORKING_DIR/.env"
    chmod 600 "$WORKING_DIR/.env"
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
render_template \
        "$TEMPLATE_DIR/.env.example.txt" \
        "$WORKING_DIR/.env"

    chown $SERVICE_USER:$SERVICE_GROUP "$WORKING_DIR/.env"
    chmod 600 "$WORKING_DIR/.env"
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
render_template \
        "$TEMPLATE_DIR/.env.example.txt" \
        "$WORKING_DIR/.env"

    chown $SERVICE_USER:$SERVICE_GROUP "$WORKING_DIR/.env"
    chmod 600 "$WORKING_DIR/.env"
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
render_template \
        "$TEMPLATE_DIR/.env.example.txt" \
        "$WORKING_DIR/.env"

    chown $SERVICE_USER:$SERVICE_GROUP "$WORKING_DIR/.env"
    chmod 600 "$WORKING_DIR/.env"
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The script uses pip with --break-system-packages while running as root, explicitly bypassing PEP 668 protections to alter the global system Python environment. This can overwrite or conflict with distro-managed packages, destabilize the host, and create a broad blast radius unrelated to the camera service itself.

Credential Access

High
Category
Privilege Escalation
Content
# 服务部署后复制为 .env 并根据需要修改

# 服务配置
HOST=0.0.0.0
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
WorkingDirectory={{WORKING_DIR}}

# 环境变量
# 注意:其他配置在 {{WORKING_DIR}}/.env 文件中管理
Environment="PYTHONPATH={{WORKING_DIR}}"
Environment="PATH={{WORKING_DIR}}/venv/bin:/usr/local/bin:/usr/bin:/bin"
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
WorkingDirectory={{WORKING_DIR}}

# 环境变量
# 注意:其他配置在 {{WORKING_DIR}}/.env 文件中管理
Environment="PYTHONPATH={{WORKING_DIR}}"
Environment="PATH={{WORKING_DIR}}/venv/bin:/usr/local/bin:/usr/bin:/bin"
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
systemctl disable "$SERVICE_NAME" 2>/dev/null || true

        log_info "删除服务文件..."
        rm -f "/etc/systemd/system/${SERVICE_NAME}.service"
        systemctl daemon-reload
    else
        log_warn "服务未安装"
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
remove_logrotate() {
    if [ -f "/etc/logrotate.d/${SERVICE_NAME}" ]; then
        log_info "删除日志轮转配置..."
        rm -f "/etc/logrotate.d/${SERVICE_NAME}"
    fi
}
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Possible Typosquatting: 'uvicorn' resembles popular package 'gunicorn'

High
Category
Supply Chain
Confidence
70% confidence
Finding
Package name closely resembles a popular package, suggesting possible typosquatting. Attackers publish malicious packages with similar names to trick developers into installing them.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill advertises and documents capabilities that inherently require network, shell, and environment access, yet the manifest does not declare any tool scope or permissions boundaries. This creates a transparency and containment failure: an agent or reviewer cannot easily understand or restrict what the skill may invoke, increasing the chance of unexpected command execution, network exposure, or access to sensitive local state.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The manifest description says the skill triggers when one 'needs to take a photo,' 'needs to observe the current view for a period,' or 'needs to pay attention to the progress of something.' These conditions are broad, lack concrete boundaries or negative examples, and could cause unintended invocation in many ordinary contexts.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The user-facing description in the manifest is written in Chinese and does not indicate that other languages are supported or that Chinese is required for a region-specific reason. This can violate language/locale policy when a skill forces a specific language without user opt-in.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The skill captures images/video and manages recorded files, but the description lacks a clear warning about privacy, retention, and data access implications. In a camera context, omission of privacy disclosures increases the chance of collecting, storing, or sharing sensitive visual data without informed user consent.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The documentation emphasizes capture and recording but also includes listing, downloading, and deleting historical outputs, which changes the risk profile from transient media capture to persistent media management. This matters because recorded media can contain sensitive images or video and should be treated as retained data subject to access control and disclosure.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This markdown file documents functions for recording video and taking photos, which can affect privacy and user data. Under SQP-2 for markdown files, the skill description should include a clear warning about privacy-sensitive behavior, but no such warning appears near the feature overview or usage examples.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
技能清单描述将该技能定位为使用摄像头拍照、录制视频或生成 GIF 的能力,但本文件还公开了下载输出文件、列出全部输出文件、删除远程文件以及查询服务状态等文件管理/服务管理接口。这些能力不只是实现拍摄本身的显而易见细节,而是扩展到了对服务端存储内容的管理。

Static analysis

No suspicious patterns detected.