Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions .github/workflows/devin-on-label.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Devin on "devin" label
on:
issues:
types: [labeled]

permissions:
contents: read
issues: write

jobs:
create-devin-session:
if: github.event.label.name == 'devin'
runs-on: ubuntu-latest
steps:
- name: Build prompt
run: |
cat > prompt.txt <<'EOF'
Work on this issue:
${{ github.event.issue.html_url }}

Title: ${{ github.event.issue.title }}

Body:
${{ github.event.issue.body }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Script injection via unsanitized user input in shell

High Severity

User-controlled values github.event.issue.body and github.event.issue.title are interpolated directly into run shell scripts via ${{ }} expressions. GitHub Actions expands these before the shell executes, so an attacker can craft an issue body containing EOF on its own line to terminate the heredoc and execute arbitrary commands — including exfiltrating the DEVIN_API_KEY secret. The title similarly breaks out of double quotes on the jq --arg line. These values need to be passed through env: blocks instead of inline interpolation.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 52802c6. Configure here.


REQUIREMENTS:
- When you open a PR, include this exact line in the PR description:
Fixes ${{ github.repository }}#${{ github.event.issue.number }}
- For every commit message in that PR, include:
Refs ${{ github.repository }}#${{ github.event.issue.number }}
EOF

- name: Create Devin session
id: devin
env:
DEVIN_API_KEY: ${{ secrets.DEVIN_API_KEY }}
run: |
set -eo pipefail
resp=$(curl -fSs https://api.devin.ai/v1/sessions \
-H "Authorization: Bearer $DEVIN_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --rawfile prompt prompt.txt \
--arg title "Issue #${{ github.event.issue.number }}: ${{ github.event.issue.title }}" \
--arg repo "${{ github.repository }}" \
--arg issue "${{ github.event.issue.number }}" \
'{prompt:$prompt, title:$title, idempotent:true,
tags:["src:github","label:devin","repo:"+$repo,"issue:"+$issue]}')")
echo "url=$(echo "$resp" | jq -er '.url')" >> "$GITHUB_OUTPUT"
echo "is_new_session=$(echo "$resp" | jq -r '.is_new_session // true')" >> "$GITHUB_OUTPUT"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jq alternative operator converts false to true

Medium Severity

The jq expression .is_new_session // true uses the alternative operator, which replaces both null and false with the right-hand side. When the Devin API returns "is_new_session": false for a duplicate session, this expression incorrectly evaluates to true, causing the workflow to always post a comment — even for already-existing sessions.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 52802c6. Configure here.


- name: Comment session link
if: steps.devin.outputs.is_new_session == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
jq -n --arg url "${{ steps.devin.outputs.url }}" \
'{body: "Devin is on it.\n\n**Session:** \($url)"}' | \
curl -sS -X POST \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
--data @- \
"https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/comments"
Loading