-
Notifications
You must be signed in to change notification settings - Fork 7
fix: harden one-shot-token binary against ELF reconnaissance #776
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,7 @@ coverage/ | |
| .nyc_output/ | ||
| *.swp | ||
| *.swo | ||
| *.so | ||
| *~ | ||
| .idea/ | ||
|
|
||
|
|
||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,26 +9,27 @@ LINK_FILE="${SCRIPT_DIR}/one-shot-token.so" | |
|
|
||
| echo "[build] Building one-shot-token with Cargo..." | ||
|
|
||
| cd "${SCRIPT_DIR}" | ||
|
|
||
| # Build the release version | ||
| cargo build --release | ||
|
|
||
| # Determine the output file based on platform | ||
| if [[ "$(uname)" == "Darwin" ]]; then | ||
| OUTPUT_FILE="${SCRIPT_DIR}/target/release/libone_shot_token.dylib" | ||
| echo "[build] Successfully built: ${OUTPUT_FILE} (macOS)" | ||
| else | ||
| OUTPUT_FILE="${SCRIPT_DIR}/target/release/libone_shot_token.so" | ||
| echo "[build] Successfully built: ${OUTPUT_FILE}" | ||
|
|
||
| # Create symlink for backwards compatibility (Linux only) | ||
| if [[ -L "${LINK_FILE}" ]]; then | ||
| rm "${LINK_FILE}" | ||
| fi | ||
| ln -sf "target/release/libone_shot_token.so" "${LINK_FILE}" | ||
| echo "[build] Created symlink: ${LINK_FILE} -> target/release/libone_shot_token.so" | ||
| fi | ||
| # Compile as a shared library with hardened build flags: | ||
| # -shared: create a shared library | ||
| # -fPIC: position-independent code (required for shared libs) | ||
| # -fvisibility=hidden: hide all symbols by default (only getenv/secure_getenv | ||
| # are exported via __attribute__((visibility("default")))) | ||
| # -ldl: link with libdl for dlsym | ||
| # -lpthread: link with pthread for mutex | ||
| # -O2: optimize for performance | ||
| # -Wall -Wextra: enable warnings | ||
| # -s: strip symbol table and relocation info at link time | ||
| gcc -shared -fPIC \ | ||
| -fvisibility=hidden \ | ||
| -O2 -Wall -Wextra -s \ | ||
| -o "${OUTPUT_FILE}" \ | ||
| "${SOURCE_FILE}" \ | ||
| -ldl -lpthread | ||
|
|
||
| # Remove remaining unneeded symbols (debug sections, build metadata) | ||
| strip --strip-unneeded "${OUTPUT_FILE}" | ||
|
|
||
| echo "[build] Successfully built: ${OUTPUT_FILE}" | ||
|
|
||
| # Verify it's a valid shared library | ||
| if file "${OUTPUT_FILE}" | grep -qE "shared object|dynamically linked"; then | ||
|
|
@@ -37,3 +38,11 @@ else | |
| echo "[build] ERROR: Output is not a valid shared library" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Verify hardening: token names should NOT appear in binary | ||
| if strings -a "${OUTPUT_FILE}" | grep -qE '(COPILOT_GITHUB_TOKEN|OPENAI_API_KEY|ANTHROPIC_API_KEY)'; then | ||
| echo "[build] WARNING: Cleartext token names still present in binary" | ||
| exit 1 | ||
| else | ||
| echo "[build] Verified: no cleartext token names in binary" | ||
| fi | ||
|
Comment on lines
+42
to
+48
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| #!/bin/bash | ||
| # Generate XOR-obfuscated byte arrays for default token names. | ||
| # Run this script whenever the default token list changes, then paste | ||
| # the output into one-shot-token.c (replacing the OBFUSCATED_DEFAULTS section). | ||
| # | ||
| # The obfuscation prevents token names from appearing as cleartext strings | ||
| # in the .rodata section of the compiled binary. This is NOT cryptographic | ||
| # security -- a determined attacker can reverse the XOR. The goal is to | ||
| # defeat casual reconnaissance via strings(1) / objdump. | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| KEY=0x5A | ||
|
|
||
| TOKENS=( | ||
| "COPILOT_GITHUB_TOKEN" | ||
| "GITHUB_TOKEN" | ||
| "GH_TOKEN" | ||
| "GITHUB_API_TOKEN" | ||
| "GITHUB_PAT" | ||
| "GH_ACCESS_TOKEN" | ||
| "OPENAI_API_KEY" | ||
| "OPENAI_KEY" | ||
| "ANTHROPIC_API_KEY" | ||
| "CLAUDE_API_KEY" | ||
| "CODEX_API_KEY" | ||
| ) | ||
|
|
||
| echo "/* --- BEGIN GENERATED OBFUSCATED DEFAULTS (key=0x$(printf '%02X' $KEY)) --- */" | ||
| echo "/* Re-generate with: containers/agent/one-shot-token/encode-tokens.sh */" | ||
| echo "#define NUM_DEFAULT_TOKENS ${#TOKENS[@]}" | ||
| echo "" | ||
|
|
||
| for i in "${!TOKENS[@]}"; do | ||
| token="${TOKENS[$i]}" | ||
| printf "static const unsigned char OBF_%d[] = { " "$i" | ||
| for ((j=0; j<${#token}; j++)); do | ||
| byte=$(printf '%d' "'${token:$j:1}") | ||
| encoded=$((byte ^ KEY)) | ||
| if ((j > 0)); then | ||
| printf ", " | ||
| fi | ||
| printf "0x%02x" "$encoded" | ||
| done | ||
| printf " }; /* length=%d */\n" "${#token}" | ||
| done | ||
|
|
||
| echo "" | ||
| echo "static const struct obf_entry OBFUSCATED_DEFAULTS[${#TOKENS[@]}] = {" | ||
| for i in "${!TOKENS[@]}"; do | ||
| echo " { OBF_${i}, sizeof(OBF_${i}) }," | ||
| done | ||
| echo "};" | ||
| echo "/* --- END GENERATED OBFUSCATED DEFAULTS --- */" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The hardening verification relies on
strings, which may not be installed by default on all dev machines (it’s typically provided by binutils). Consider checkingcommand -v stringsand failing with a clear message (or skipping verification) rather than failing with a generic “command not found”.This issue also appears on line 30 of the same file.