docs(audit): update hardening report to focus exclusively on attacker-extractable artifacts
هذا الالتزام موجود في:
@@ -1,328 +1,161 @@
|
||||
# 🛡️ Ghaymah CLI v2 — Binary Hardening & DevSecOps Compliance Report
|
||||
# 🛡️ Ghaymah CLI v2 — Attacker-Accessible Surface & Binary Hardening Audit
|
||||
|
||||
> **Target Artifact:** `gy-linux-amd64` (Production Release Candidate)
|
||||
> **Source:** `https://cliv2.ghaymah.systems/gy-linux-amd64`
|
||||
> **Auditor:** Senior CI/CD Artifact Auditor & DevSecOps QA
|
||||
> **Auditor:** DevSecOps QA & Threat Modeling Assessment
|
||||
> **Date:** September 20, 2026
|
||||
> **Compliance Status:** **PARTIALLY COMPLIANT (2/3 Hardening Directives Passed)** ⚠️
|
||||
> **Focus:** 100% Verifiable, Extracted Artifacts Available to an External Attacker
|
||||
|
||||
---
|
||||
|
||||
## 📊 Executive Summary Checklist
|
||||
|
||||
| Hardening Directive | Compiler/Tool Flag | Required State | Actual State | Status |
|
||||
|---------------------|--------------------|----------------|--------------|--------|
|
||||
| **Symbol Stripping** | `-ldflags="-s"` | No `.symtab` / `.strtab` | Absent (Stripped) | ✅ **PASS** |
|
||||
| **Debug Info Stripping** | `-ldflags="-w"` | No DWARF `.debug_*` sections | Absent (Stripped) | ✅ **PASS** |
|
||||
| **Path Obfuscation** | `-trimpath` | Zero developer machine paths | Zero leaks (`/home/`, `C:\Users\`) | ✅ **PASS** |
|
||||
| **Binary Compression** | `upx --best --lzma` | Packed (`UPX0`, `UPX1`, `UPX!`) | Uncompressed (11.69 MB) | ❌ **FAIL** |
|
||||
| **TLS Pinset Integrity** | Hardcoded SHA-256 | 4 Valid Base64 Hashes | All 4 Pins Intact | ✅ **PASS** |
|
||||
| Hardening Directive | Compiler/Tool Flag | Required State | Actual State | Attacker Accessibility | Status |
|
||||
|---------------------|--------------------|----------------|--------------|------------------------|--------|
|
||||
| **Symbol Stripping** | `-ldflags="-s"` | No `.symtab` / `.strtab` | Absent | **Inaccessible** (Symbols removed) | ✅ **PASS** |
|
||||
| **Debug Info Stripping** | `-ldflags="-w"` | No DWARF `.debug_*` sections | Absent | **Inaccessible** (DWARF removed) | ✅ **PASS** |
|
||||
| **Path Obfuscation** | `-trimpath` | Zero developer machine paths | Zero leaks | **Inaccessible** (No `/home/` or `C:\Users\`) | ✅ **PASS** |
|
||||
| **Binary Compression** | `upx --best --lzma` | Packed (`UPX0`, `UPX1`, `UPX!`) | Uncompressed (11.69 MB) | 🔴 **EXPOSED** (Plaintext strings in `.rodata`) | ❌ **FAIL** |
|
||||
| **Token Storage** | Local Encryption | AES-GCM Encrypted | Plaintext JSON | 🔴 **EXPOSED** (Accessible via `config.json`) | ❌ **FAIL** |
|
||||
| **TLS Pinset Integrity** | Hardcoded SHA-256 | 4 Valid Base64 Hashes | 4 Hashes in binary | 🟡 **VISIBLE** (Extracted via strings) | ✅ **PASS** |
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ System & Binary Architecture
|
||||
## 🏗️ Reconstructed Attack Topology (Extracted via Static Analysis)
|
||||
|
||||
The diagram below illustrates the end-to-end architecture of **Ghaymah CLI v2**, showing the relationship between local CLI security subsystems, client-side encryption, and the backend cloud microservices infrastructure:
|
||||
Using **only** data extracted from the uncompressed `gy-linux-amd64` binary and local filesystem artifacts, an attacker can reconstruct the complete backend microservice topology without access to source code:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "Local Client Environment (gy-linux-amd64)"
|
||||
CLI["CLI Commands (Cobra)<br><code>deploy</code>, <code>login</code>, <code>tunnel</code>, <code>delete</code>"]
|
||||
|
||||
subgraph "Security Enforcement Layer"
|
||||
VALIDATOR["Input Validator (CWE-20)<br>Regex: <code>^[a-z0-9-]+$</code>"]
|
||||
SCANNER["Pre-Deploy Scanner v1.0.0<br>Dockerfile & .dockerignore Linter"]
|
||||
SYMLINK["Symlink Guard (T1027)<br><code>filepath.EvalSymlinks</code>"]
|
||||
end
|
||||
|
||||
subgraph "Storage & Crypto Layer"
|
||||
CRYPTO["Crypto Module (CWE-312 Fix)<br>AES-256-GCM + Machine-ID"]
|
||||
CONFIG_FILE["Local Store<br><code>~/.config/ghaymah/cli/nhost/config.json</code>"]
|
||||
end
|
||||
|
||||
subgraph "Network Transport Layer"
|
||||
TRANSPORT["Secure Transport (T1557)<br>Proxy Bypass + 4-Pin TLS Pinset"]
|
||||
end
|
||||
subgraph "Attacker-Controlled Local Host"
|
||||
ATTACKER["Attacker / Local Process"]
|
||||
BINARY["gy-linux-amd64<br>(11.69 MB Unpacked ELF)"]
|
||||
CONF["~/.config/ghaymah/cli/nhost/config.json<br>🔴 Plaintext Tokens Stored Here"]
|
||||
end
|
||||
|
||||
subgraph "Ghaymah Cloud Infrastructure (*.ghaymah.systems)"
|
||||
AUTH_SRV["Auth Engine<br><code>auth.ghaymah.systems</code>"]
|
||||
GQL_SRV["Hasura GraphQL Engine<br><code>graphql.ghaymah.systems</code>"]
|
||||
S3_SRV["S3 Storage Proxy<br><code>s3-nhost-proxy-*.hosted.ghaymah.systems</code>"]
|
||||
LOGS_SRV["Logs Streaming Server<br><code>logs.ghaymah.systems</code>"]
|
||||
GENAI_SRV["GenAI LiteLLM Gateway<br><code>genai.ghaymah.systems</code>"]
|
||||
subgraph "Exposed Backend Endpoints (Extracted from .rodata)"
|
||||
AUTH["auth.ghaymah.systems<br>(Nhost Authentication API)"]
|
||||
GQL["graphql.ghaymah.systems<br>(Hasura GraphQL API)"]
|
||||
S3["s3-nhost-proxy-83e02743fd61.hosted.ghaymah.systems<br>🔴 Exposed Object Storage Proxy"]
|
||||
LOGS["logs.ghaymah.systems<br>(Log Streaming Server)"]
|
||||
GENAI["genai.ghaymah.systems<br>(LiteLLM AI Service)"]
|
||||
REG["registry.ghaymah.systems<br>(Container Registry)"]
|
||||
CLI_SRV["cli.ghaymah.systems / cliv2.ghaymah.systems<br>(Update & Distribution Host)"]
|
||||
end
|
||||
|
||||
CLI --> VALIDATOR
|
||||
VALIDATOR --> SCANNER
|
||||
SCANNER --> SYMLINK
|
||||
SYMLINK --> TRANSPORT
|
||||
|
||||
CLI <--> CRYPTO
|
||||
CRYPTO <--> CONFIG_FILE
|
||||
|
||||
TRANSPORT -- "Bypasses HTTP_PROXY<br>Direct TLS with Key Pinning" --> AUTH_SRV
|
||||
TRANSPORT -- "GraphQL Operations" --> GQL_SRV
|
||||
TRANSPORT -- "Container Bundles" --> S3_SRV
|
||||
TRANSPORT -- "Live Log Streams" --> LOGS_SRV
|
||||
TRANSPORT -- "AI Detection" --> GENAI_SRV
|
||||
ATTACKER -- "1. Read plaintext refreshToken" --> CONF
|
||||
ATTACKER -- "2. Extract strings & endpoints" --> BINARY
|
||||
ATTACKER -- "3. Direct API calls using stolen token" --> AUTH
|
||||
ATTACKER -- "4. Direct GraphQL queries/mutations" --> GQL
|
||||
ATTACKER -- "5. Direct artifact upload / probing" --> S3
|
||||
ATTACKER -- "6. Inspect container images" --> REG
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Phase 1: Build Metadata & Symbol Verification
|
||||
## 🕵️♂️ Extracted Artifacts & Attacker-Accessible Surface
|
||||
|
||||
### ELF Section Header Table Analysis
|
||||
Analysis of the 64-bit ELF binary structure yielded **16 section headers**:
|
||||
The data below represents **only what an attacker can directly extract** from the binary and local configuration using standard analysis tools (`strings`, `grep`, `cat`):
|
||||
|
||||
### 1. Extracted Backend Endpoints & Domains (`.rodata`)
|
||||
These URLs were extracted directly from the uncompressed data segments of `gy-linux-amd64`:
|
||||
|
||||
```text
|
||||
Section Headers (16 total):
|
||||
[ 1] .note.go.buildid
|
||||
[ 2] .note.gnu.build-id
|
||||
[ 3] .text
|
||||
[ 4] .rodata
|
||||
[ 5] .gopclntab
|
||||
[ 6] .go.type
|
||||
[ 7] .go.func
|
||||
[ 8] .go.buildinfo
|
||||
[ 9] .go.fipsinfo
|
||||
[10] .go.module
|
||||
[11] .noptrdata
|
||||
[12] .data
|
||||
[13] .bss
|
||||
[14] .noptrbss
|
||||
[15] .shstrtab
|
||||
auth.ghaymah.systems
|
||||
graphql.ghaymah.systems
|
||||
logs.ghaymah.systems
|
||||
genai.ghaymah.systems
|
||||
registry.ghaymah.systems
|
||||
cli.ghaymah.systems
|
||||
s3-nhost-proxy-83e02743fd61.hosted.ghaymah.systems
|
||||
foundhosted.ghaymah.systems
|
||||
```
|
||||
|
||||
### Symbol & Debug Evaluation
|
||||
- **`.symtab` (Symbol Table):** **ABSENT** ✅
|
||||
- **`.strtab` (Symbol String Table):** **ABSENT** ✅
|
||||
- **DWARF Debug Sections (`.debug_info`, `.debug_line`, etc.):** **ABSENT** ✅
|
||||
> [!CAUTION]
|
||||
> **Attacker Advantage:** The specific S3 proxy subdomain (`s3-nhost-proxy-83e02743fd61.hosted.ghaymah.systems`) reveals the exact storage gateway used for project build context uploads, allowing an attacker to probe the storage service directly without using the CLI.
|
||||
|
||||
---
|
||||
|
||||
### 2. Extracted Internal Go Packages & Architecture (`.gopclntab`)
|
||||
Even with `-s -w` applied, Go's runtime program counter line table retains package import paths. An attacker extracts:
|
||||
|
||||
```text
|
||||
gitlab.com/ghaymah/go-utils
|
||||
gitlab.com/ghaymah/go-utils/config
|
||||
gitlab.com/ghaymah/go-utils/nhost
|
||||
gitlab.com/ghaymah/go-utils/graphql
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> The Go linker flags `-ldflags="-s -w"` were correctly applied during compilation. The binary does not contain standard symbol tables or DWARF debugging symbols, making trivial symbol restoration impossible.
|
||||
> This reveals that Ghaymah CLI v2 is architected around `go-utils` with dedicated Nhost auth and Hasura GraphQL client modules.
|
||||
|
||||
---
|
||||
|
||||
## 📦 Phase 2: Compression & Packer Integrity Check
|
||||
### 3. Extracted TLS Public Key Pinset Hashes
|
||||
The 4 SHA-256 certificate public key hashes are visible in cleartext in the binary:
|
||||
|
||||
### UPX Header & Magic Byte Inspection
|
||||
- **`UPX0` Section Header:** **NOT FOUND** ❌
|
||||
- **`UPX1` Section Header:** **NOT FOUND** ❌
|
||||
- **`UPX!` Magic Marker:** **NOT FOUND** ❌
|
||||
- **Artifact File Size:** **12,259,488 bytes (11.69 MB)**
|
||||
|
||||
> [!WARNING]
|
||||
> ### ⚠️ Compliance Non-Conformity: UPX Packing Omitted
|
||||
> The production artifact was deployed without the required UPX compression stage (`upx --best --lzma`).
|
||||
> - **Expected Size:** ~3.7 MB (as achieved in reference builds).
|
||||
> - **Actual Size:** 11.69 MB (+214% size bloat).
|
||||
> - **DevSecOps Impact:**
|
||||
> 1. **Bandwidth & Latency:** Slower download and distribution times for end users during `curl | sh` installations.
|
||||
> 2. **Static Analysis Exposure:** Without compression, all Go runtime metadata (`.gopclntab`), string literals, and backend endpoints remain exposed to basic string extraction without requiring decompression.
|
||||
|
||||
---
|
||||
|
||||
## 🧹 Phase 3: Artifact Cleanliness & Data Privacy (String Analysis)
|
||||
|
||||
### 1. Developer Machine Path Verification (`-trimpath`)
|
||||
The compiled artifact was searched for file path patterns that reveal developer usernames, internal directory layouts, or host operating systems:
|
||||
|
||||
- Windows User Directories (`C:\Users\...`): **0 matches** ✅
|
||||
- Linux Home Directories (`/home/...`): **0 matches** ✅
|
||||
- macOS User Directories (`/Users/...`): **0 matches** ✅
|
||||
|
||||
> [!TIP]
|
||||
> The Go `-trimpath` compiler flag was successfully enforced. All internal package paths are cleanly mapped relative to the module root (e.g., `gitlab.com/ghaymah/...` and standard library paths) with zero local environment leakage.
|
||||
|
||||
### 2. TLS Pinset Cryptographic Marker Verification
|
||||
The artifact contains all 4 mandatory SHA-256 public key pinset hashes:
|
||||
|
||||
| Domain Target | Expected Pinset Hash (Base64) | Found in Binary | Status |
|
||||
|---------------|-------------------------------|-----------------|--------|
|
||||
| `graphql.ghaymah.systems` | `deRrEjh64wYgxRJ15ayqnD8aBMGHkjGDhegIOZzN3iw=` | **YES** | ✅ Verified |
|
||||
| `auth.ghaymah.systems` | `Jmmi4aU72CahnGAT6ZT6yvWeSv1g1lhahkiK5RDipn8=` | **YES** | ✅ Verified |
|
||||
| `s3-storage.ghaymah.systems` | `T/t6LfgixGVf2RPIMpusT0c7memko1cGuHVTMRRyTqY=` | **YES** | ✅ Verified |
|
||||
| `logs.ghaymah.systems` | `zSJTbrWU36arxt/HzAm7GrMc5op3vsJkUlBDxj4jLHI=` | **YES** | ✅ Verified |
|
||||
|
||||
---
|
||||
|
||||
## 💻 Source Code Reference & Hardening Implementation
|
||||
|
||||
To resolve the identified non-compliances and maintain security parity with the Windows release candidate, the following production source code implementations must be enforced:
|
||||
|
||||
### 1. Secure Transport & TLS Pinset (`cmd/root.go`)
|
||||
Implements **T1557 mitigations** by bypassing local system proxies and verifying leaf certificates against the hardcoded pinset:
|
||||
|
||||
```go
|
||||
// setupSecureTransport implements T1557 mitigations:
|
||||
// 1. Ignores system proxies for authentication.
|
||||
// 2. Warns the user if a proxy is detected.
|
||||
// 3. Employs strict TLS Public Key Pinning.
|
||||
func setupSecureTransport() {
|
||||
proxies := []string{"HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy"}
|
||||
for _, p := range proxies {
|
||||
if os.Getenv(p) != "" {
|
||||
printWarn("Security Warning: A system proxy (%s) was detected. It will be ignored for authentication to prevent credential interception.", p)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// T1557: Real SHA-256 Public Key Pinset for *.ghaymah.systems
|
||||
validPins := []string{
|
||||
"deRrEjh64wYgxRJ15ayqnD8aBMGHkjGDhegIOZzN3iw=", // graphql.ghaymah.systems
|
||||
"Jmmi4aU72CahnGAT6ZT6yvWeSv1g1lhahkiK5RDipn8=", // auth.ghaymah.systems
|
||||
"T/t6LfgixGVf2RPIMpusT0c7memko1cGuHVTMRRyTqY=", // s3 storage proxy
|
||||
"zSJTbrWU36arxt/HzAm7GrMc5op3vsJkUlBDxj4jLHI=", // logs.ghaymah.systems
|
||||
}
|
||||
|
||||
http.DefaultTransport = &http.Transport{
|
||||
Proxy: nil, // Ignore system proxies for auth & API traffic
|
||||
TLSClientConfig: &tls.Config{
|
||||
VerifyConnection: func(cs tls.ConnectionState) error {
|
||||
if len(cs.PeerCertificates) == 0 {
|
||||
return errors.New("no certificates provided by server")
|
||||
}
|
||||
|
||||
// The first certificate is always the leaf certificate
|
||||
leaf := cs.PeerCertificates[0]
|
||||
hash := sha256.Sum256(leaf.RawSubjectPublicKeyInfo)
|
||||
encodedHash := base64.StdEncoding.EncodeToString(hash[:])
|
||||
|
||||
for _, pin := range validPins {
|
||||
if encodedHash == pin {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("TLS Pinning failed: public key mismatch. Got %s, which is not in the trusted pinset", encodedHash)
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Machine-ID AES-256-GCM Token Encryption (`cmd/crypto.go`)
|
||||
Resolves **CWE-312 (Plaintext Storage)** by encrypting `config.json` on disk using an AES key derived from the local hardware Machine ID:
|
||||
|
||||
```go
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/denisbrodbeck/machineid"
|
||||
"gitlab.com/ghaymah/go-utils/config"
|
||||
)
|
||||
|
||||
const encPrefix = "GY_ENC:"
|
||||
|
||||
func getEncryptionKey() ([]byte, error) {
|
||||
// Derive key from hardware Machine UUID + appID
|
||||
id, err := machineid.ProtectedID(appID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hash := sha256.Sum256([]byte(id))
|
||||
return hash[:], nil
|
||||
}
|
||||
|
||||
// LockConfig encrypts config.json with AES-GCM prior to process exit
|
||||
func LockConfig() {
|
||||
path, err := config.UserConfigPath(filepath.Join(appID, "nhost"), "")
|
||||
if err != nil { return }
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil || len(data) == 0 || strings.HasPrefix(string(data), encPrefix) {
|
||||
return
|
||||
}
|
||||
|
||||
key, err := getEncryptionKey()
|
||||
if err != nil { return }
|
||||
|
||||
block, _ := aes.NewCipher(key)
|
||||
gcm, _ := cipher.NewGCM(block)
|
||||
|
||||
nonce := make([]byte, gcm.NonceSize())
|
||||
io.ReadFull(rand.Reader, nonce)
|
||||
|
||||
ciphertext := gcm.Seal(nonce, nonce, data, nil)
|
||||
os.WriteFile(path, append([]byte(encPrefix), ciphertext...), 0600)
|
||||
}
|
||||
|
||||
// UnlockConfig decrypts config.json into memory when CLI commands execute
|
||||
func UnlockConfig() {
|
||||
path, err := config.UserConfigPath(filepath.Join(appID, "nhost"), "")
|
||||
if err != nil { return }
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil || !strings.HasPrefix(string(data), encPrefix) {
|
||||
return
|
||||
}
|
||||
|
||||
key, err := getEncryptionKey()
|
||||
if err != nil { return }
|
||||
|
||||
ciphertext := data[len(encPrefix):]
|
||||
block, _ := aes.NewCipher(key)
|
||||
gcm, _ := cipher.NewGCM(block)
|
||||
|
||||
nonceSize := gcm.NonceSize()
|
||||
if len(ciphertext) < nonceSize { return }
|
||||
|
||||
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
|
||||
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
|
||||
if err == nil {
|
||||
os.WriteFile(path, plaintext, 0600)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Strict Regex Input Validation (`cmd/deploy.go`)
|
||||
Resolves **CWE-20 (Input Validation / SQLi / XSS)**:
|
||||
|
||||
```go
|
||||
var appNameRegex = regexp.MustCompile(`^[a-z0-9-]+$`)
|
||||
|
||||
func validateAppName(name string) error {
|
||||
if name == "" {
|
||||
return errors.New("app name cannot be empty")
|
||||
}
|
||||
if len(name) > 63 {
|
||||
return fmt.Errorf("app name '%s' is too long (maximum 63 characters)", name)
|
||||
}
|
||||
if !appNameRegex.MatchString(name) {
|
||||
return fmt.Errorf("invalid app name '%s' — use only lowercase letters, numbers, and hyphens", name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```text
|
||||
deRrEjh64wYgxRJ15ayqnD8aBMGHkjGDhegIOZzN3iw=
|
||||
Jmmi4aU72CahnGAT6ZT6yvWeSv1g1lhahkiK5RDipn8=
|
||||
T/t6LfgixGVf2RPIMpusT0c7memko1cGuHVTMRRyTqY=
|
||||
zSJTbrWU36arxt/HzAm7GrMc5op3vsJkUlBDxj4jLHI=
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Remediation & CI/CD Action Items
|
||||
### 4. Extracted Security Rules & Error Messages
|
||||
By analyzing string literals, an attacker can reverse-engineer input validation and scanner logic without reading source code:
|
||||
|
||||
To bring the build pipeline into full 100% compliance with production hardening standards:
|
||||
```text
|
||||
# Input Validation Rule Leakage:
|
||||
"invalid app name '%s' — use only letters, numbers, and hyphens (no spaces or slashes)"
|
||||
|
||||
1. **Add UPX Step to CI/CD Release Pipeline:**
|
||||
```bash
|
||||
# 1. Build binary with symbol stripping and path obfuscation
|
||||
go build -ldflags="-s -w" -trimpath -o dist/gy-linux-amd64 .
|
||||
# Proxy Detection Leakage:
|
||||
"Security Warning: A system proxy (%s) was detected. It will be ignored for authentication to prevent credential interception."
|
||||
|
||||
# 2. Compress with UPX LZMA (Required step)
|
||||
upx --best --lzma dist/gy-linux-amd64
|
||||
```
|
||||
# Pre-Deploy Scanner Leakage:
|
||||
"Wildcard COPY/ADD Detected — Sensitive File Leakage Risk"
|
||||
"Container Runs as Root User"
|
||||
"Lines [%s] use wildcard copy instructions (COPY . / or ADD . /) which will include ALL files"
|
||||
"TLS Pinning failed: public key mismatch. Got %s, which is not in the trusted pinset"
|
||||
```
|
||||
|
||||
2. **Automate Hardening Verification Gate in CI/CD:**
|
||||
Add an automated test step prior to uploading binaries to `cliv2.ghaymah.systems`:
|
||||
- Fail pipeline if binary size > 5 MB.
|
||||
- Fail pipeline if `.symtab` is detected in section headers.
|
||||
- Fail pipeline if developer username or local path regex matches.
|
||||
- Fail pipeline if `config.json` is saved in cleartext without `GY_ENC:` prefix.
|
||||
---
|
||||
|
||||
### 5. Extracted Plaintext Credentials (CWE-312)
|
||||
Directly extracted from `~/.config/ghaymah/cli/nhost/config.json` on the local machine:
|
||||
|
||||
```json
|
||||
{
|
||||
"token": {
|
||||
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3ODk5NDk4NzQsImh0dHBzOi8vaGFzdXJhLmlvL2p3dC9jbGFpbXMiOnsieC1oYXN1cmEtYWxsb3dlZC1yb2xlcyI6WyJtZSIsInVzZXIiXSwieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoidXNlciIsIngtaGFzdXJhLXVzZXItaWQiOiJkNjJmOTg4Ni1mY2VkLTRjZjItOThlNC01YjYyMDAwZDRmMDMiLCJ4LWhhc3VyYS11c2VyLWlzLWFub255bW91cyI6ImZhbHNlIn0sImlhdCI6MTc4OTg1OTg3NCwiaXNzIjoiaGFzdXJhLWF1dGgiLCJzdWIiOiJkNjJmOTg4Ni1mY2VkLTRjZjItOThlNC01YjYyMDAwZDRmMDMifQ...",
|
||||
"refreshToken": "11a90303-237e-467b-b324-54d6ef6e5cf5",
|
||||
"expiresAt": "2026-09-21T00:17:53.875260112Z",
|
||||
"userId": "d62f9886-fced-4cf2-98e4-5b62000d4f03"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> **Critical Finding:** An attacker who accesses this file gains full, perpetual access to the user's Ghaymah cloud account via the `refreshToken`, completely bypassing the CLI.
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ What the Attacker CANNOT Access (Verified Defenses)
|
||||
|
||||
Despite the string leaks, the following security barriers were successfully verified:
|
||||
|
||||
1. **No Developer Machine Paths:** Searching for `C:\Users\`, `/home/`, or `/Users/` yielded **0 matches**. The `-trimpath` flag completely stripped build environment paths.
|
||||
2. **No High-Level Source Code / Comments:** Symbol stripping (`-s -w`) removed all `.symtab`, `.strtab`, and DWARF debugging data. The attacker cannot reconstruct the original Go source code or variable names.
|
||||
3. **No Credential Interception via Proxy:** Setting `HTTP_PROXY` or `HTTPS_PROXY` fails to capture traffic because the binary explicitly ignores proxies for authentication.
|
||||
4. **No Direct Injection via CLI Flags:** Attempts to pass SQLi, XSS, or Path Traversal in `--name` or `--id` are blocked locally by regex before any network request is sent.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Remediation Priority Checklist
|
||||
|
||||
| Priority | Issue | Threat Vector | Fix Action |
|
||||
|----------|-------|---------------|------------|
|
||||
| 🔴 **P0** | **Plaintext Tokens (CWE-312)** | Local account takeover via `config.json` | Encrypt `config.json` with AES-256-GCM using Machine ID salt. |
|
||||
| 🟡 **P1** | **Uncompressed Binary (CWE-200)** | Trivial endpoint & architecture extraction | Apply `upx --best --lzma` to scramble string data and reduce size by ~70%. |
|
||||
| 🟢 **P2** | **Internal Package Names** | Reconnaissance via `.gopclntab` | Use Go build obfuscators (e.g., `garble`) if full symbol obfuscation is required. |
|
||||
|
||||
المرجع في مشكلة جديدة
حظر مستخدم