Spaces:
Running
Download SECURITY.md from codey-lab/Universal-AI-Hub: direct link, hf CLI and curl.
- Browser
- Download file 6.68 kB
-
https://huggingface.co/spaces/codey-lab/Universal-AI-Hub/resolve/main/SECURITY.md
- Command line
-
hf download hf://spaces/codey-lab/Universal-AI-Hub/SECURITY.md
-
curl -L -o SECURITY.md https://huggingface.co/spaces/codey-lab/Universal-AI-Hub/resolve/main/SECURITY.md
Security Policy
Reporting a Vulnerability
If you find a security issue, please do not open a public GitHub issue.
Report privately via: GitHub Security Advisories
Include: what you found, how to reproduce it, and what impact you think it has. You'll get a response within 72 hours. If the issue is confirmed, a fix will be prioritized before any public disclosure.
Security Architecture
The Guardian Pattern
main.py is the only process that ever touches secrets. It reads .env / HF Space Secrets, initializes fundaments/* conditionally, and passes the results into app/* as a validated dict. After that handoff, app/* has no path back to the raw environment.
.env / HF Secrets
β
βΌ
main.py (Guardian) β only entry point
β
β initializes fundaments/* conditionally
β injects as: fundaments = {"config": ..., "db": ..., "encryption": ..., ...}
β
βΌ
app/app.py β unpacks fundaments ONCE at startup, never stores globally
β
βββ app/* modules β read only from app/.pyfun, never from os.environ
This is enforced structurally. app/* has no import of fundaments/, no os.environ calls, no .env access. It's not a coding convention β it's an import boundary.
Secret Handling
- API keys live exclusively in HF Space Secrets or
.envβ never inapp/.pyfun, never in source code app/.pyfunreferences only ENV variable names (e.g.env_key = "ANTHROPIC_API_KEY") β never valueslist_active_toolsreturns key names only β the actual key values are never exposed through any MCP toolfundaments/modules are initialized only if their required ENV vars are present β missing config = service skipped, not crashed
Encryption (fundaments/encryption.py)
When MASTER_ENCRYPTION_KEY and PERSISTENT_ENCRYPTION_SALT are set:
- Key derivation: PBKDF2-HMAC-SHA256, 480,000 iterations, 256-bit output
- Encryption: AES-256-GCM β authenticated encryption, provides both confidentiality and integrity
- Each encryption operation uses a fresh random 96-bit nonce
- Authentication tag (128-bit) is stored alongside ciphertext β decryption fails loudly if data was tampered
- File encryption uses streaming with 8 KB chunks β nonce prepended, tag appended to file
- If encryption keys are not set, the service is skipped cleanly β the app runs without it
Authentication (fundaments/user_handler.py)
- Passwords hashed with PBKDF2-SHA256 via
passlib - Sessions stored in SQLite with IP address + User-Agent binding β
validate_session()checks both - Session IDs are regenerated on login (session fixation prevention)
- Failed login attempts tracked per user β account locks after 5 consecutive failures
- Session table uses
ON DELETE CASCADEβ deleting a user removes all their sessions automatically
Access Control (fundaments/access_control.py)
- Role-based permission system backed by PostgreSQL (cloud DB, Guardian-only)
- Schema:
users β user_role_assignments β user_roles β role_permissions β user_permissions - All queries use parameterized statements via
asyncpgβ no string interpolation has_permission()checks the full roleβpermission chain per requestAccessControlonly initializes if a DB connection is available β degrades gracefully otherwise
Database Security (fundaments/postgresql.py)
Cloud DB (asyncpg pool):
- SSL enforced at minimum
sslmode=requireβ upgraded automatically if not set - Neon.tech quirks handled:
statement_timeoutstripped from DSN (unsupported, causes silent failures), keepalives set - Credentials masked in all log output β full DSN only in
DEBUGlevel logs - SSL runtime check via
pg_stat_sslon every new connection (cloud providers: warning only if unavailable) - Automatic pool restart on Neon connection termination (sqlstate
08006) - Pool: min 1 / max 10 connections, connect timeout 5s, command timeout 30s
Internal SQLite (app/db_sync.py + fundaments/user_handler.py):
- Same SQLite file, separate tables β zero overlap enforced by code
users+sessionsβ owned byuser_handler.py(Guardian layer)hub_state+tool_cacheβ owned bydb_sync.py(app/* layer)db_queryMCP tool exposes SELECT-only access tohub_stateandtool_cacheβ cannot reachusersorsessions- SELECT enforcement: non-SELECT queries raise
ValueErrorbefore execution - On HuggingFace Spaces: SQLite auto-relocated to
/tmp/(HF filesystem is read-only outside/tmp/)
MCP Transport Security
- All MCP traffic routes through Quart
/mcpendpoint before reaching FastMCP - This is the natural interception point for auth checks, rate limiting, and payload logging β none are optional add-ons
/cryptoendpoint exists but returns501until the app-layer encryption wrapper is implemented β not bypassed, not silently ignoredhealth_checkandlist_active_toolsare always available β they expose no secrets, only status and key names
Sandboxing Rules
These rules are enforced by code structure, not just documentation:
| Rule | Enforced by |
|---|---|
app/* never reads os.environ |
No os.environ calls in any app/ file |
app/* never imports fundaments/ |
No cross-imports between layers |
fundaments/ services injected, not constructed in app/* |
start_application(fundaments) signature |
Direct execution of app/app.py blocked |
__main__ guard with null-fundaments warning |
db_query tool is SELECT-only |
ValueError raised before any non-SELECT execution |
API keys never in .pyfun |
.pyfun parser only reads key names, never resolves them |
What This Project Does Not Claim
- It is not a penetration-tested security product
- The encrypted
/cryptoendpoint is not yet implemented - Search provider implementations (Brave, Tavily) are pending β the tool registers as placeholder
- This is a personal/community project β use in production at your own assessment
PyFundaments is not perfect. But it's more secure than most of what runs in production today.
Supported Versions
| Version | Supported |
|---|---|
latest (main) |
β |
| older forks | β β fork at your own risk |
License Note
This project is dual-licensed under Apache 2.0 and the Ethical Security Operations License v1.1 (ESOL). Using this software for surveillance, unauthorized access, or harm to others automatically terminates your license.