Skip to main content

presidio-hardened-opcua

Hardened OPC UA wrapper with Presidio security extensions.

CI License: MIT

Drop-in replacement for python-opcua that adds strong security defaults, certificate validation, anomaly detection, and input sanitization — all without changing your existing OPC UA code.

Security notice — CVE-2022-25304. The underlying opcua (python-opcua 0.98.13) is unmaintained and has no fix for this memory-exhaustion issue. Since 0.2.0 this package bounds chunk size, chunk count and message size process-wide on import, so scanners will still flag opcua but the attack is mitigated. See SECURITY.md.

Installation

pip install presidio-hardened-opcua

Quick Start

Replace your existing import:

# Before (plain opcua)
from opcua import Client, Server

# After (Presidio-hardened)
from presidio_opcua import Client, Server

That's it. Your existing code gains security hardening automatically.

Side-by-Side Comparison

Plain opcua — no security enforced

from opcua import Client

client = Client("opc.tcp://10.0.0.5:4840")
client.connect()  # ← connects with NO encryption
node = client.get_node("ns=2;i=1")  # ← no input sanitization
value = node.get_value()
client.disconnect()

Problems: No certificate validation, no encryption requirement, no anomaly detection, no input sanitization. An attacker on the network can eavesdrop, tamper, or inject malicious node IDs.

presidio-hardened-opcua — secure by default

from presidio_opcua import Client, SecurityPolicy

policy = SecurityPolicy(
    allow_self_signed=False,  # reject self-signed certs
    session_timeout_ms=30_000,  # tight session timeout
)

client = Client("opc.tcp://10.0.0.5:4840", security_policy=policy)

# Security is enforced — this will FAIL without calling set_security() first:
# client.connect()  → raises PresidioSecurityError

# Configure mutual authentication:
client.set_security(
    "Basic256Sha256",
    certificate_path="client_cert.der",
    private_key_path="client_key.pem",
    server_certificate_path="server_cert.der",
    # mode defaults to SignAndEncrypt — cannot be set to None
)

client.connect()  # ✓ encrypted, authenticated, hardened timeouts

# Node IDs are automatically sanitized:
node = client.get_node("ns=2;i=1")  # ✓ validated
value = node.get_value()

# Anomaly detection runs in the background:
print(client.anomaly_detector.stats)

client.disconnect()

Server — insecure policies automatically rejected

from presidio_opcua import Server
from opcua import ua

server = Server()

# NoSecurity is silently filtered out:
server.set_security_policy(
    [
        ua.SecurityPolicyType.NoSecurity,  # ← rejected
        ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt,  # ← kept
    ]
)

server.start()

Security Features

Feature Description
Certificate Validation Rejects self-signed certs by default; validates expiry and format
Strict Security Mode Enforces SignAndEncrypt; rejects None security mode
Input Sanitization Validates node IDs, browse paths, and variant values against injection patterns
Anomaly Detection Monitors access rate and unique-node counts; logs warnings on suspicious activity
Dependency CVE Check Checks installed versions of opcua and cryptography against known vulnerabilities
Message Limits Bounds chunk size, chunk count and message size (CVE-2022-25304)
Session Hardening Configurable session and channel timeouts (defaults: 30s / 60s)
Security Event Logging All security decisions logged via Python logging under presidio_opcua.*

Configuration

from presidio_opcua import SecurityPolicy

policy = SecurityPolicy(
    allow_self_signed=False,  # reject self-signed certificates
    allow_no_security=False,  # reject None security mode
    session_timeout_ms=30_000,  # session timeout in milliseconds
    secure_channel_timeout_ms=60_000,  # secure channel timeout
)

Message limits (CVE-2022-25304)

from presidio_opcua import Client, Server

server = Server(max_chunk_count=256, max_message_size=16 * 1024 * 1024)
client = Client("opc.tcp://10.0.0.5:4840", max_chunk_size=1024 * 1024)

Defaults: 64 MiB per chunk, 1601 chunks per message, 100 MiB per message. Environment overrides: PRESIDIO_OPCUA_MAX_CHUNK_SIZE, PRESIDIO_OPCUA_MAX_CHUNK_COUNT, PRESIDIO_OPCUA_MAX_MESSAGE_SIZE. The guards apply to every opcua connection in the process; the keyword arguments set limits for that instance only.

Logging

Enable security event logging:

import logging

logging.basicConfig(level=logging.INFO)

# All Presidio security events are logged under:
#   presidio_opcua.client
#   presidio_opcua.server
#   presidio_opcua.security
#   presidio_opcua.anomaly
#   presidio_opcua.dep_check
#   presidio_opcua.limits

Development

git clone https://github.com/presidio-v/presidio-hardened-opcua.git
cd presidio-hardened-opcua
pip install -e ".[dev]"
pytest --cov=presidio_opcua
ruff check .

License

MIT — see LICENSE.


SDLC

This repository is on the open-source baseline of the PRESIDIO hardened-family SDLC (report · PDF). The controls measured for it, and any open gaps, are its row in the applicability matrix.

Metadata

Release files for presidio-hardened-opcua 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for presidio-hardened-opcua 0.2.0
File Size Uploaded Provenance Actions
presidio_hardened_opcua-0.2.0.tar.gz 59.4 kB With provenance Details for presidio_hardened_opcua-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for presidio-hardened-opcua 0.2.0
File Interpreter ABI Platform Actions
presidio_hardened_opcua-0.2.0-py3-none-any.whl Python 3 none any Details for presidio_hardened_opcua-0.2.0-py3-none-any.whl

Total release size: 76.9 kB

Release files / presidio_hardened_opcua-0.2.0.tar.gz

Download URL presidio_hardened_opcua-0.2.0.tar.gz
Size 59.4 kB
Tags Source
SHA-256 checksum
How to use checksums
a30e07b1be634315fa47550634fb2c3483fdd877c3b6f71cf8cdfc8dcfe58674
BLAKE2b-256 checksum
How to use checksums
d69f57437d5a847ee7163d8ea92fff67640e7ffff113c05bdafda886966f8a0f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

Release files / presidio_hardened_opcua-0.2.0-py3-none-any.whl

Download URL presidio_hardened_opcua-0.2.0-py3-none-any.whl
Size 17.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
55e1c377ca2d28a9a8f48ae3f29e2c60bcd2304b537bc27226cac8831b309f01
BLAKE2b-256 checksum
How to use checksums
16e4a8dc2e4f1b9ea18c9f484dbad93515fbcac8f9b3cfd025cd5ebee544e6b9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

Security for presidio-hardened-opcua 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for presidio_hardened_opcua-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page