From 7da1e6e8ac775558adb4ac8661ba65fd708bcc2e Mon Sep 17 00:00:00 2001 From: comimit775 Date: Sun, 31 May 2026 06:58:03 +0000 Subject: [PATCH] fix: replace hardcoded secrets with GitHub Secrets refs, prevent credential logging, mitigate script injection - Replace hardcoded RDP_USER/RDP_PASS with ${{ secrets.RDP_USER }}/${{ secrets.RDP_PASS }} - Remove password from Write-Host log output in Workflow 1 - Replace ts_api_key, ts_authkey, ts_tailnet workflow inputs with ${{ secrets.* }} references - Route all workflow inputs through env: blocks to prevent script injection - Remove Administrators group membership for RDP user (keep Remote Desktop Users only) Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../RDP + Tailscale (STOP & RESTART).yml | 46 ++++++++++--------- .../RDP + Tailscale (Workflow 1).yml | 43 +++++++++-------- .../RDP + Tailscale (Workflow 2).yml | 35 +++++++------- 3 files changed, 68 insertions(+), 56 deletions(-) diff --git a/.github/workflows/RDP + Tailscale (STOP & RESTART).yml b/.github/workflows/RDP + Tailscale (STOP & RESTART).yml index 3b1d854..c04f53e 100644 --- a/.github/workflows/RDP + Tailscale (STOP & RESTART).yml +++ b/.github/workflows/RDP + Tailscale (STOP & RESTART).yml @@ -3,9 +3,6 @@ name: RDP + Tailscale (STOP & RESTART) on: workflow_dispatch: inputs: - ts_tailnet: { description: "Tailscale tailnet", required: true } - ts_api_key: { description: "Tailscale API key", required: true } - ts_authkey: { description: "Tailscale Auth key", required: true } quick_test: { description: "Restart with 5-min test", type: boolean, default: false } runtime_minutes: { description: "Runtime for restart", required: false, default: "355" } do_purge: { description: "Purge bullet devices", required: false, default: "true" } @@ -25,10 +22,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Purge bullet* devices + env: + TS_API_KEY: ${{ secrets.TS_API_KEY }} + TS_TAILNET: ${{ secrets.TS_TAILNET }} run: | try{ - $auth=[Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("${{ inputs.ts_api_key }}:")) - $tn=[uri]::EscapeDataString("${{ inputs.ts_tailnet }}") + $auth=[Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$($env:TS_API_KEY):")) + $tn=[uri]::EscapeDataString($env:TS_TAILNET) $list=Invoke-RestMethod "https://api.tailscale.com/api/v2/tailnet/$tn/devices" -Headers @{Authorization="Basic $auth"} $count=0 foreach($d in $list.devices){ @@ -37,18 +37,20 @@ jobs: $count++ } } - Write-Host "๐Ÿงน Removed $count bullet devices from Tailscale." - }catch{Write-Host "โš ๏ธ Cleanup failed: $($_.Exception.Message)"} + Write-Host "Removed $count bullet devices from Tailscale." + }catch{Write-Host "Cleanup failed: $($_.Exception.Message)"} - name: Decide next step id: next + env: + INPUT_CYCLES_LEFT: ${{ inputs.cycles_left }} run: | - $left=[int]"${{ inputs.cycles_left }}" + $left=[int]$env:INPUT_CYCLES_LEFT if($left -le 0){ - Write-Host "โœ… 5 cycles completed. Stopping permanently." + Write-Host "All cycles completed. Stopping permanently." "RESTART=0"|Out-File -Append $env:GITHUB_ENV }else{ - Write-Host "โณ Waiting 20 min before restarting Workflow 1. Cycles left: $left" + Write-Host "Waiting 20 min before restarting Workflow 1. Cycles left: $left" "RESTART=1"|Out-File -Append $env:GITHUB_ENV } @@ -56,27 +58,29 @@ jobs: if: env.RESTART == '1' run: | $end=(Get-Date).AddMinutes(20) - while((Get-Date) -lt $end){Write-Host ("๐Ÿ•’ Cooling down "+(Get-Date));Start-Sleep 60} + while((Get-Date) -lt $end){Write-Host ("Cooling down "+(Get-Date));Start-Sleep 60} - name: Restart Workflow 1 (if cycles remain) if: env.RESTART == '1' env: GH_TOKEN: ${{ github.token }} + INPUT_CYCLES_LEFT: ${{ inputs.cycles_left }} + INPUT_QUICK_TEST: ${{ inputs.quick_test }} + INPUT_RUNTIME_MINUTES: ${{ inputs.runtime_minutes }} + INPUT_DO_PURGE: ${{ inputs.do_purge }} + INPUT_RDP_COUNT: ${{ inputs.rdp_count }} run: | - $next=[int]"${{ inputs.cycles_left }}"-1 - if($next -le 0){Write-Host "โœ… Finished all cycles.";exit 0} + $next=[int]$env:INPUT_CYCLES_LEFT-1 + if($next -le 0){Write-Host "Finished all cycles.";exit 0} $payload=@{ - ts_tailnet="${{ inputs.ts_tailnet }}" - ts_api_key="${{ inputs.ts_api_key }}" - ts_authkey="${{ inputs.ts_authkey }}" - quick_test="${{ inputs.quick_test }}" - runtime_minutes="${{ inputs.runtime_minutes }}" - do_purge="${{ inputs.do_purge }}" - rdp_count="${{ inputs.rdp_count }}" + quick_test=$env:INPUT_QUICK_TEST + runtime_minutes=$env:INPUT_RUNTIME_MINUTES + do_purge=$env:INPUT_DO_PURGE + rdp_count=$env:INPUT_RDP_COUNT cycles_left="$next" } $url="https://api.github.com/repos/${{ github.repository }}/actions/workflows/workflow-1.yml/dispatches" $hdr=@{Authorization="Bearer $env:GH_TOKEN";Accept="application/vnd.github+json"} $body=@{ref="${{ github.ref_name }}";inputs=$payload}|ConvertTo-Json -Depth 20 Invoke-WebRequest -Method POST -Uri $url -Headers $hdr -Body $body|Out-Null - Write-Host "๐Ÿš€ Workflow 1 restarted (cycles left: $next)" + Write-Host "Workflow 1 restarted (cycles left: $next)" diff --git a/.github/workflows/RDP + Tailscale (Workflow 1).yml b/.github/workflows/RDP + Tailscale (Workflow 1).yml index 6ac5c95..bb26476 100644 --- a/.github/workflows/RDP + Tailscale (Workflow 1).yml +++ b/.github/workflows/RDP + Tailscale (Workflow 1).yml @@ -3,9 +3,6 @@ name: RDP + Tailscale (Workflow 1) on: workflow_dispatch: inputs: - ts_tailnet: { description: "Tailscale tailnet (e.g. you@gmail.com)", required: true } - ts_api_key: { description: "Tailscale API key (device admin, no Bearer)", required: true } - ts_authkey: { description: "Tailscale Auth key", required: true } quick_test: { description: "Run 5-minute test", type: boolean, default: false } runtime_minutes: { description: "Runtime minutes", required: false, default: "355" } do_purge: { description: "Purge bullet* devices", required: false, default: "true" } @@ -27,8 +24,10 @@ jobs: matrix: ${{ steps.mk.outputs.matrix }} steps: - id: mk + env: + INPUT_RDP_COUNT: ${{ inputs.rdp_count }} run: | - $n=[int]"${{ inputs.rdp_count }}" + $n=[int]$env:INPUT_RDP_COUNT if($n -lt 1){$n=1}; if($n -gt 10){$n=10} $arr=@(); for($i=1;$i -le $n;$i++){ $arr+=@{id=$i} } $json=@{include=$arr}|ConvertTo-Json -Compress @@ -41,19 +40,24 @@ jobs: matrix: ${{ fromJson(needs.setup.outputs.matrix) }} timeout-minutes: 370 env: - RDP_USER: Bullettemporary - RDP_PASS: Bullet@12345 + RDP_USER: ${{ secrets.RDP_USER }} + RDP_PASS: ${{ secrets.RDP_PASS }} steps: - name: Decide runtime + env: + INPUT_QUICK_TEST: ${{ inputs.quick_test }} + INPUT_RUNTIME_MINUTES: ${{ inputs.runtime_minutes }} run: | function Yes($v){ "$v" -match '^(?i:true|1|yes|on)$' } - $rt=if(Yes("${{ inputs.quick_test }}")){5}else{[int]"${{ inputs.runtime_minutes }}"} + $rt=if(Yes($env:INPUT_QUICK_TEST)){5}else{[int]$env:INPUT_RUNTIME_MINUTES} if($rt -gt 360){$rt=355} "RUNTIME_MINUTES=$rt"|Out-File -Append $env:GITHUB_ENV Write-Host "Runtime set to $rt minutes" - name: Install + Configure Tailscale + env: + TS_AUTHKEY: ${{ secrets.TS_AUTHKEY }} run: | $ts="$env:ProgramFiles\Tailscale\tailscale.exe" if(-not(Test-Path $ts)){ @@ -62,7 +66,7 @@ jobs: Invoke-WebRequest $url -OutFile $dst Start-Process msiexec.exe -ArgumentList "/i","`"$dst`"","/quiet","/norestart" -Wait } - & $ts up --authkey "${{ inputs.ts_authkey }}" --hostname "bullet1" --accept-dns=true + & $ts up --authkey $env:TS_AUTHKEY --hostname "bullet1" --accept-dns=true $ip=& $ts ip -4 |Select-Object -First 1 "TAILSCALE_IP=$ip"|Out-File -Append $env:GITHUB_ENV Write-Host "Tailscale IPv4: $ip" @@ -73,12 +77,11 @@ jobs: $s=ConvertTo-SecureString $p -AsPlainText -Force if(-not(Get-LocalUser -Name $u -EA SilentlyContinue)){ New-LocalUser -Name $u -Password $s -AccountNeverExpires - Add-LocalGroupMember -Group "Administrators" -Member $u Add-LocalGroupMember -Group "Remote Desktop Users" -Member $u } Set-ItemProperty "HKLM:\System\CurrentControlSet\Control\Terminal Server" fDenyTSConnections 0 Enable-NetFirewallRule -DisplayGroup "Remote Desktop" - Write-Host "RDP ready: $u / $p @ $env:TAILSCALE_IP" + Write-Host "RDP ready for user $u @ $env:TAILSCALE_IP" - name: Install Python libs run: | @@ -94,20 +97,22 @@ jobs: if: always() env: GH_TOKEN: ${{ github.token }} + INPUT_CYCLES_LEFT: ${{ inputs.cycles_left }} + INPUT_QUICK_TEST: ${{ inputs.quick_test }} + INPUT_RUNTIME_MINUTES: ${{ inputs.runtime_minutes }} + INPUT_DO_PURGE: ${{ inputs.do_purge }} + INPUT_RDP_COUNT: ${{ inputs.rdp_count }} run: | - $next=[int]"${{ inputs.cycles_left }}"-1 + $next=[int]$env:INPUT_CYCLES_LEFT-1 $payload=@{ - ts_tailnet="${{ inputs.ts_tailnet }}" - ts_api_key="${{ inputs.ts_api_key }}" - ts_authkey="${{ inputs.ts_authkey }}" - quick_test="${{ inputs.quick_test }}" - runtime_minutes="${{ inputs.runtime_minutes }}" - do_purge="${{ inputs.do_purge }}" - rdp_count="${{ inputs.rdp_count }}" + quick_test=$env:INPUT_QUICK_TEST + runtime_minutes=$env:INPUT_RUNTIME_MINUTES + do_purge=$env:INPUT_DO_PURGE + rdp_count=$env:INPUT_RDP_COUNT cycles_left="$next" } $url="https://api.github.com/repos/${{ github.repository }}/actions/workflows/workflow-2.yml/dispatches" $hdr=@{Authorization="Bearer $env:GH_TOKEN";Accept="application/vnd.github+json"} $body=@{ref="${{ github.ref_name }}";inputs=$payload}|ConvertTo-Json -Depth 20 Invoke-WebRequest -Method POST -Uri $url -Headers $hdr -Body $body|Out-Null - Write-Host "โžก๏ธ Workflow 2 triggered. Cycles left: $next" + Write-Host "Workflow 2 triggered. Cycles left: $next" diff --git a/.github/workflows/RDP + Tailscale (Workflow 2).yml b/.github/workflows/RDP + Tailscale (Workflow 2).yml index e82f0ff..10c30ba 100644 --- a/.github/workflows/RDP + Tailscale (Workflow 2).yml +++ b/.github/workflows/RDP + Tailscale (Workflow 2).yml @@ -3,9 +3,6 @@ name: RDP + Tailscale (Workflow 2) on: workflow_dispatch: inputs: - ts_tailnet: { description: "Tailscale tailnet", required: true } - ts_api_key: { description: "Tailscale API key", required: true } - ts_authkey: { description: "Tailscale Auth key", required: true } quick_test: { description: "Run 5-min test", type: boolean, default: false } runtime_minutes: { description: "Runtime", required: false, default: "355" } do_purge: { description: "Purge bullet devices", required: false, default: "true" } @@ -25,11 +22,13 @@ jobs: runs-on: windows-latest timeout-minutes: 370 env: - RDP_USER: Bullettemporary - RDP_PASS: Bullet@12345 + RDP_USER: ${{ secrets.RDP_USER }} + RDP_PASS: ${{ secrets.RDP_PASS }} steps: - name: Setup Tailscale + RDP + env: + TS_AUTHKEY: ${{ secrets.TS_AUTHKEY }} run: | $ts="$env:ProgramFiles\Tailscale\tailscale.exe" if(-not(Test-Path $ts)){ @@ -38,7 +37,7 @@ jobs: Invoke-WebRequest $url -OutFile $dst Start-Process msiexec.exe -ArgumentList "/i","`"$dst`"","/quiet","/norestart" -Wait } - & $ts up --authkey "${{ inputs.ts_authkey }}" --hostname "bullet2" --accept-dns=true + & $ts up --authkey $env:TS_AUTHKEY --hostname "bullet2" --accept-dns=true Enable-NetFirewallRule -DisplayGroup "Remote Desktop" - name: Install Python libs @@ -47,8 +46,10 @@ jobs: python -m pip install --force-reinstall pyautogui pynput pillow - name: Keep alive + env: + INPUT_RUNTIME_MINUTES: ${{ inputs.runtime_minutes }} run: | - $rt=[int]"${{ inputs.runtime_minutes }}" + $rt=[int]$env:INPUT_RUNTIME_MINUTES $end=(Get-Date).AddMinutes($rt) while((Get-Date) -lt $end){Write-Host ("Workflow2 heartbeat "+(Get-Date));Start-Sleep 60} @@ -56,19 +57,21 @@ jobs: if: always() env: GH_TOKEN: ${{ github.token }} + INPUT_QUICK_TEST: ${{ inputs.quick_test }} + INPUT_RUNTIME_MINUTES: ${{ inputs.runtime_minutes }} + INPUT_DO_PURGE: ${{ inputs.do_purge }} + INPUT_RDP_COUNT: ${{ inputs.rdp_count }} + INPUT_CYCLES_LEFT: ${{ inputs.cycles_left }} run: | $payload=@{ - ts_tailnet="${{ inputs.ts_tailnet }}" - ts_api_key="${{ inputs.ts_api_key }}" - ts_authkey="${{ inputs.ts_authkey }}" - quick_test="${{ inputs.quick_test }}" - runtime_minutes="${{ inputs.runtime_minutes }}" - do_purge="${{ inputs.do_purge }}" - rdp_count="${{ inputs.rdp_count }}" - cycles_left="${{ inputs.cycles_left }}" + quick_test=$env:INPUT_QUICK_TEST + runtime_minutes=$env:INPUT_RUNTIME_MINUTES + do_purge=$env:INPUT_DO_PURGE + rdp_count=$env:INPUT_RDP_COUNT + cycles_left=$env:INPUT_CYCLES_LEFT } $url="https://api.github.com/repos/${{ github.repository }}/actions/workflows/workflow-stop.yml/dispatches" $hdr=@{Authorization="Bearer $env:GH_TOKEN";Accept="application/vnd.github+json"} $body=@{ref="${{ github.ref_name }}";inputs=$payload}|ConvertTo-Json -Depth 20 Invoke-WebRequest -Method POST -Uri $url -Headers $hdr -Body $body|Out-Null - Write-Host "๐Ÿ›‘ STOP workflow triggered (cycles left: ${{ inputs.cycles_left }})" + Write-Host "STOP workflow triggered (cycles left: $env:INPUT_CYCLES_LEFT)"