Metadata-Version: 2.4
Name: oubliette-sec-utils
Version: 0.1.0
Summary: Shared security helpers for Oubliette Shield / Sentinel / Dungeon / Trap / sift-guard.
Author-email: Oubliette Security <info@oubliettesecurity.com>
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/oubliettesecurity/oubliette-sec-utils
Project-URL: Issues, https://github.com/oubliettesecurity/oubliette-sec-utils/issues
Keywords: security,ssrf,path-traversal,argument-injection,ai-security
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Security
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: ruff>=0.15; extra == "dev"
Dynamic: license-file

# oubliette-sec-utils

Shared security helpers for the Oubliette product family (Shield, Sentinel,
Dungeon, Trap, sift-guard).

Extracted from duplicated inline code that was flagged in the 2026-04-22
red-team audit as the source of recurring cross-repo security fixes:

- **Path scope** — `contained_in()` + `safe_realpath()` replace the broken
  `startswith` / `normpath` pattern. A sibling directory like
  `/evidence-stolen` no longer passes the scope check for `/evidence`.
- **Argument injection** — `validate_argument()` / `validate_allowlist()`
  reject strings that start with `-`, contain shell metacharacters, or
  aren't in a whitelisted set. `shell=False` does NOT protect against
  argv-level injection.
- **SSRF** — `is_ip_safe()` / `validate_outbound_url()` reject private,
  loopback, link-local, reserved, multicast, IPv6-mapped IPv4, and the
  Fly.io 6PN ULA range (`fdaa::/16`), which `ipaddress.is_private`
  misses. URL validation performs DNS resolution and checks every
  resolved IP (rebinding defence).

## Install

```bash
pip install oubliette-sec-utils
```

## Usage

```python
from oubliette_sec_utils import (
    contained_in, safe_realpath,
    validate_argument, validate_allowlist,
    is_ip_safe, validate_outbound_url,
)

# Path scope
assert contained_in("/evidence/disk.E01", "/evidence") is True
assert contained_in("/evidence-stolen/disk.E01", "/evidence") is False

# Argv injection
d = validate_argument("SYSTEM --plugins /tmp/evil.pl", allow_spaces=True)
assert d.blocked is True

# SSRF
d = validate_outbound_url("http://169.254.169.254/latest/meta-data/")
assert d.safe is False
```

## Scope and non-goals

This package is a **helper library**, not a framework. It does not know
about Flask, FastAPI, MCP, or any specific subsystem — callers wrap these
helpers into their own request pipelines. That separation is deliberate:
Shield, Sentinel, Dungeon, Trap, and sift-guard all have different
framework shapes, but they share the same underlying validation needs.

## License

Apache 2.0
