Skip to content

Security: Autonomy-Logic/openplc-runtime

Security

docs/SECURITY.md

Security

Overview

OpenPLC Runtime v4 implements multiple layers of security to protect against common vulnerabilities and ensure safe operation in industrial environments.

TLS/HTTPS

Self-Signed Certificates

The runtime automatically generates self-signed TLS certificates on first run:

Certificate Files:

  • webserver/certOPENPLC.pem - Certificate
  • webserver/keyOPENPLC.pem - Private key

Certificate Details:

  • Key size: 2048-bit RSA
  • Validity: 365 days
  • Subject: CN=localhost
  • Subject Alternative Names: localhost, 127.0.0.1, and detected IP addresses

Implementation: webserver/credentials.py

Certificate Generation

The certificate generation process includes security validations:

  1. Hostname Validation: Prevents command injection in hostname field
  2. IP Address Validation: Ensures valid IP format
  3. Path Validation: Prevents path traversal in certificate file paths
  4. Automatic Renewal: Checks certificate validity and regenerates if expired

Key Functions:

CertGen.generate_self_signed_cert(cert_file, key_file)
CertGen.is_certificate_valid(cert_file)

Using Custom Certificates

To use custom certificates (e.g., from Let's Encrypt):

  1. Replace webserver/certOPENPLC.pem with your certificate
  2. Replace webserver/keyOPENPLC.pem with your private key
  3. Ensure certificate includes all necessary hostnames/IPs
  4. Restart the runtime

Certificate Chain: If using a certificate chain, concatenate certificates:

cat your_cert.pem intermediate.pem root.pem > certOPENPLC.pem

Authentication

JWT Tokens

The runtime uses JSON Web Tokens (JWT) for authentication:

Token Storage:

  • Secret key stored in /var/run/runtime/.env
  • 256-bit hexadecimal secret (64 characters)
  • Generated automatically on first run

Token Usage:

  • WebSocket debug interface requires JWT authentication
  • Tokens obtained via REST API login endpoint
  • Tokens can be revoked by regenerating secret

Environment Variable:

JWT_SECRET_KEY=<64-character-hex-string>

Password Security

User passwords are protected with multiple layers:

  1. Hashing: Passwords hashed using secure algorithm
  2. Salting: Unique salt per user
  3. Pepper: Global 256-bit pepper stored in .env
  4. Database: Stored in /var/run/runtime/restapi.db

Environment Variable:

PEPPER=<64-character-hex-string>

Configuration Management

The .env file is automatically generated with secure defaults:

Location: /var/run/runtime/.env

Contents:

SQLALCHEMY_DATABASE_URI=sqlite:////var/run/runtime/restapi.db
JWT_SECRET_KEY=<auto-generated>
PEPPER=<auto-generated>

Permissions:

  • File created with restricted permissions
  • Only accessible by runtime user
  • Should not be committed to version control

Implementation: webserver/config.py

File Upload Security

ZIP File Validation

Uploaded ZIP files undergo comprehensive security checks before extraction:

Path Traversal Prevention

Checks:

  • No absolute paths (starting with /)
  • No parent directory references (..)
  • No drive letters (: character)
  • Extraction paths validated to stay within destination

Example Blocked Paths:

/etc/passwd
../../../etc/passwd
C:\Windows\System32

Size Limits

Limits:

  • Maximum file size: 10 MB per file
  • Maximum total size: 50 MB uncompressed
  • Enforced before extraction

Purpose: Prevent resource exhaustion and disk space attacks

ZIP Bomb Detection

Check: Compression ratio must be ≤ 1000:1

Example:

  • Compressed: 1 KB
  • Uncompressed: 1 MB (ratio 1000:1) - Allowed
  • Uncompressed: 2 MB (ratio 2000:1) - Blocked

Purpose: Prevent decompression bombs that exhaust disk space or memory

Extension Whitelist

Blocked Extensions:

  • .exe - Windows executables
  • .dll - Dynamic libraries
  • .sh - Shell scripts
  • .bat - Batch files
  • .js - JavaScript files
  • .vbs - VBScript files
  • .scr - Screen savers (often malware)

Purpose: Prevent execution of malicious code

macOS Metadata Removal

Removed:

  • __MACOSX/ directory
  • .DS_Store files

Purpose: Clean up unnecessary metadata that could contain sensitive information

Implementation: webserver/plcapp_management.py

Safe Extraction

The extraction process includes additional safety measures:

  1. Root Folder Stripping: Automatically removes single root folder
  2. Path Normalization: Converts all paths to absolute and validates
  3. Directory Creation: Creates necessary subdirectories safely
  4. Atomic Operations: Extraction is all-or-nothing

Stored Source Project

A device keeps a copy of the source project it is running so it can be retrieved later (see RETRIEVE_PROJECT.md). Its security properties are deliberately narrow, and worth stating plainly.

It is not encrypted. The project is a plain ZIP file under the persistent data directory. Anyone who can read the device's filesystem can read the project -- over SSH, with physical access, from a backup image, or from a mounted volume in a container deployment.

The access control is one role check. GET /api/project-snapshot refuses the archive to anyone who is not an administrator. That protects the network path and nothing else; it is not a second layer behind encryption, because there is no encryption behind it.

There is no integrity guarantee. Nothing signs or checksums the stored project. A project replaced on disk is retrieved as if it were the original, and neither the device nor the client can tell.

The project name is advertised unauthenticated. The UDP discovery reply on port 33333 carries the stored project's name and timestamp so clients can populate a device picker before anyone signs in. Anything on the same network can read them. The archive itself is never served over discovery.

If a deployment needs the project protected at rest, use full-disk or filesystem-level encryption on the device. This feature is not a substitute.

Process Security

Privilege Requirements

The runtime requires elevated privileges for:

  1. Real-Time Scheduling: Setting SCHED_FIFO priority
  2. Socket Creation: Creating Unix domain sockets in /run/runtime/
  3. Port Binding: Binding to port 8443 (privileged port)

Recommendation: Run with sudo or grant specific capabilities:

sudo setcap cap_sys_nice,cap_net_bind_service=+ep build/plc_main

Process Isolation

Separate Processes:

  • Web server runs as Python process
  • PLC runtime runs as separate C/C++ process
  • Communication only via Unix domain sockets

Benefits:

  • Crash in one process doesn't affect the other
  • Different privilege levels possible
  • Memory isolation

Signal Handling

The runtime handles signals gracefully:

  • SIGINT: Graceful shutdown, cleanup resources
  • SIGTERM: Graceful shutdown
  • SIGSEGV: Caught and logged (if possible)

Implementation: core/src/plc_app/plc_main.c

Network Security

Port Exposure

Default Ports:

  • 8443 (HTTPS) - REST API for OpenPLC Editor communication

Recommendations:

  • Use firewall to restrict access
  • Only expose to trusted networks
  • Consider VPN for remote access

Docker Port Mapping:

docker run -p 127.0.0.1:8443:8443 ...  # Localhost only
docker run -p 8443:8443 ...            # All interfaces

Unix Domain Sockets

Socket Locations:

  • /run/runtime/plc_runtime.socket - Command socket
  • /run/runtime/log_runtime.socket - Log socket

Security:

  • Only accessible on local system
  • File system permissions control access
  • No network exposure

Permissions:

  • Created with restricted permissions
  • Only runtime user can connect

Data Security

Database

Location: /var/run/runtime/restapi.db

Contents:

  • User accounts
  • Hashed passwords
  • Session data

Protection:

  • File system permissions
  • SQLite encryption (if configured)
  • Regular backups recommended

Logs

Sensitive Information:

  • Logs may contain variable values
  • IP addresses and connection information
  • Error messages with file paths

Recommendations:

  • Rotate logs regularly
  • Restrict log file access
  • Sanitize logs before sharing

Compiled Programs

Location: build/libplc_*.so

Contents:

  • Compiled PLC logic
  • Variable definitions
  • Custom function blocks

Protection:

  • File system permissions
  • Not transmitted over network
  • Timestamped for version control

Docker Security

Container Isolation

Benefits:

  • Process isolation from host
  • Network isolation (unless exposed)
  • File system isolation

Considerations:

  • Privileged mode may be needed for real-time scheduling
  • Volume mounts expose host directories
  • Port exposure creates network access

Volume Security

Persistent Volume:

docker run -v openplc-runtime-data:/var/run/runtime ...

Contents:

  • .env file with secrets
  • Database with user accounts
  • Compiled programs

Recommendations:

  • Use named volumes (not bind mounts)
  • Backup volumes regularly
  • Restrict volume access

Image Security

Official Image: ghcr.io/autonomy-logic/openplc-runtime:latest

Security Features:

  • Based on Debian bookworm-slim (minimal attack surface)
  • Regular updates via CI/CD
  • Multi-architecture support
  • Signed images (GitHub Container Registry)

Verification:

docker pull ghcr.io/autonomy-logic/openplc-runtime:latest
docker inspect ghcr.io/autonomy-logic/openplc-runtime:latest

Security Best Practices

Deployment

  1. Use HTTPS Only: Never disable TLS
  2. Strong Passwords: Enforce password complexity
  3. Regular Updates: Keep runtime and dependencies updated
  4. Firewall Rules: Restrict network access
  5. Monitoring: Monitor logs for suspicious activity

Development

  1. Code Review: Review all changes before merging
  2. Static Analysis: Use linters and security scanners
  3. Dependency Scanning: Check for vulnerable dependencies
  4. Input Validation: Validate all user inputs
  5. Error Handling: Don't expose sensitive information in errors

Operations

  1. Backup Regularly: Backup /var/run/runtime/ directory
  2. Rotate Secrets: Regenerate JWT secret and pepper periodically
  3. Audit Logs: Review logs for security events
  4. Update Certificates: Renew certificates before expiration
  5. Least Privilege: Run with minimum required privileges

Vulnerability Reporting

If you discover a security vulnerability:

  1. Do Not open a public issue
  2. Contact the maintainers privately
  3. Provide detailed reproduction steps
  4. Allow time for patch development
  5. Coordinate disclosure timing

Security Limitations

Known Limitations

  1. Self-Signed Certificates: Default certificates are self-signed (OpenPLC Editor handles this automatically)
  2. No Rate Limiting: API endpoints not rate-limited
  3. No Account Lockout: No protection against brute force
  4. No Audit Trail: Limited logging of security events
  5. No Encryption at Rest: Database and files not encrypted

Future Improvements

Planned security enhancements:

  • Rate limiting for API endpoints
  • Account lockout after failed attempts
  • Comprehensive audit logging
  • Database encryption at rest
  • Certificate management UI
  • Two-factor authentication
  • Role-based access control

Compliance Considerations

Industrial Standards

The runtime is designed for industrial automation but does not claim compliance with specific standards (e.g., IEC 62443). Organizations should:

  1. Conduct security assessments
  2. Implement additional controls as needed
  3. Follow industry-specific guidelines
  4. Document security configurations

Data Protection

For environments with data protection requirements (GDPR, etc.):

  1. Minimize data collection
  2. Implement data retention policies
  3. Provide data export capabilities
  4. Document data flows
  5. Implement access controls

Related Documentation

There aren't any published security advisories