diff --git a/.github/workflows/dependency-cve-monitor.yml b/.github/workflows/dependency-cve-monitor.yml index 22868167c539..9164ddb4d0c3 100644 --- a/.github/workflows/dependency-cve-monitor.yml +++ b/.github/workflows/dependency-cve-monitor.yml @@ -36,7 +36,7 @@ jobs: env: SLACK_WEBHOOK_URL: ${{ secrets.CI_SLACK_WEBHOOK_URL }} GH_TOKEN: ${{ secrets.DEPENDABOT_ALERTS_TOKEN }} - JQ_FILTER_B64: "Wy5bXSB8IHNlbGVjdCguY3JlYXRlZF9hdCA+ICRjdXRvZmYgYW5kIC5zZWN1cml0eV92dWxuZXJhYmlsaXR5LmZpcnN0X3BhdGNoZWRfdmVyc2lvbiAhPSBudWxsKV0KfCBncm91cF9ieSguc2VjdXJpdHlfdnVsbmVyYWJpbGl0eS5wYWNrYWdlLm5hbWUpCnwgbWFwKHsKICAgIHBrZzogLlswXS5zZWN1cml0eV92dWxuZXJhYmlsaXR5LnBhY2thZ2UubmFtZSwKICAgIGZpeDogLlswXS5zZWN1cml0eV92dWxuZXJhYmlsaXR5LmZpcnN0X3BhdGNoZWRfdmVyc2lvbi5pZGVudGlmaWVyLAogICAgbWFuaWZlc3RzOiAoWy5bXS5kZXBlbmRlbmN5Lm1hbmlmZXN0X3BhdGhdIHwgdW5pcXVlIHwgbWFwKGdzdWIoIi9wb20ueG1sJCI7ICIiKSB8IGdzdWIoIi4qLyI7ICIiKSkpLAogICAgY3ZlczogKGdyb3VwX2J5KC5zZWN1cml0eV9hZHZpc29yeS5jdmVfaWQgLy8gLnNlY3VyaXR5X2Fkdmlzb3J5Lmdoc2FfaWQpIHwgbWFwKHsKICAgICAgY3ZlOiAoLlswXS5zZWN1cml0eV9hZHZpc29yeS5jdmVfaWQgLy8gLlswXS5zZWN1cml0eV9hZHZpc29yeS5naHNhX2lkKSwKICAgICAgZ2hzYTogLlswXS5zZWN1cml0eV9hZHZpc29yeS5naHNhX2lkLAogICAgICBzZXZlcml0eTogKC5bMF0uc2VjdXJpdHlfYWR2aXNvcnkuc2V2ZXJpdHkgfCBhc2NpaV91cGNhc2UpCiAgICB9KSkKICB9KQp8IGlmIGxlbmd0aCA9PSAwIHRoZW4gZW1wdHkKICBlbHNlCiAgICAiOndhcm5pbmc6ICpcKG1hcCguY3ZlcyB8IGxlbmd0aCkgfCBhZGQpIG5ldyBDVkUocykgZGV0ZWN0ZWQgaW4gU0RLIGRlcGVuZGVuY2llcyB3aXRoIGZpeGVzIGF2YWlsYWJsZSpcblxuIiArCiAgICAobWFwKAogICAgICAiYFwoLnBrZylgIChcKC5tYW5pZmVzdHMgfCBqb2luKCIsICIpKSkgXHUyMTkyIFVwZ3JhZGUgdG8gYFwoLmZpeClgXG4iICsKICAgICAgKC5jdmVzIHwgbWFwKCIgIFx1MjAyMiA8aHR0cHM6Ly9naXRodWIuY29tL2Fkdmlzb3JpZXMvXCguZ2hzYSl8XCguY3ZlKT4gKFwoLnNldmVyaXR5KSkiKSB8IGpvaW4oIlxuIikpCiAgICApIHwgam9pbigiXG5cbiIpKSArCiAgICAiXG5cbipBY3Rpb24gbmVlZGVkKjogVXBncmFkZSB0aGUgYWZmZWN0ZWQgZGVwZW5kZW5jeSB2ZXJzaW9ucyB0byB0aGUgZml4IHZlcnNpb25zIGxpc3RlZCBhYm92ZS4iCiAgZW5kCg==" + JQ_FILTER_B64: "Wy5bXSB8IHNlbGVjdCguY3JlYXRlZF9hdCA+ICRjdXRvZmYgYW5kIC5zZWN1cml0eV92dWxuZXJhYmlsaXR5LmZpcnN0X3BhdGNoZWRfdmVyc2lvbiAhPSBudWxsKV0KfCBncm91cF9ieSguc2VjdXJpdHlfdnVsbmVyYWJpbGl0eS5wYWNrYWdlLm5hbWUpCnwgbWFwKHsKICAgIHBrZzogLlswXS5zZWN1cml0eV92dWxuZXJhYmlsaXR5LnBhY2thZ2UubmFtZSwKICAgIGZpeDogLlswXS5zZWN1cml0eV92dWxuZXJhYmlsaXR5LmZpcnN0X3BhdGNoZWRfdmVyc2lvbi5pZGVudGlmaWVyLAogICAgbWFuaWZlc3RzOiAoWy5bXS5kZXBlbmRlbmN5Lm1hbmlmZXN0X3BhdGhdIHwgdW5pcXVlIHwgbWFwKGdzdWIoIi9wb20ueG1sJCI7ICIiKSB8IGdzdWIoIi4qLyI7ICIiKSkpLAogICAgY3ZlczogKGdyb3VwX2J5KC5zZWN1cml0eV9hZHZpc29yeS5jdmVfaWQgLy8gLnNlY3VyaXR5X2Fkdmlzb3J5Lmdoc2FfaWQpIHwgbWFwKHsKICAgICAgY3ZlOiAoLlswXS5zZWN1cml0eV9hZHZpc29yeS5jdmVfaWQgLy8gLlswXS5zZWN1cml0eV9hZHZpc29yeS5naHNhX2lkKSwKICAgICAgZ2hzYTogLlswXS5zZWN1cml0eV9hZHZpc29yeS5naHNhX2lkLAogICAgICBzZXZlcml0eTogKC5bMF0uc2VjdXJpdHlfYWR2aXNvcnkuc2V2ZXJpdHkgfCBhc2NpaV91cGNhc2UpLAogICAgICBzdW1tYXJ5OiAoLlswXS5zZWN1cml0eV9hZHZpc29yeS5zdW1tYXJ5IHwgc3BsaXQoIi4gIikgfCBmaXJzdCB8IGlmIGxlbmd0aCA+IDE1MCB0aGVuIC5bOjE0N10gKyAiLi4uIiBlbHNlIC4gZW5kKQogICAgfSkpCiAgfSkKfCBpZiBsZW5ndGggPT0gMCB0aGVuIGVtcHR5CiAgZWxzZQogICAgIjp3YXJuaW5nOiAqXChtYXAoLmN2ZXMgfCBsZW5ndGgpIHwgYWRkKSBDVkUocykgZGV0ZWN0ZWQgdmlhIDxodHRwczovL2dpdGh1Yi5jb20vYXdzL2F3cy1zZGstamF2YS12Mi9zZWN1cml0eS9kZXBlbmRhYm90fERlcGVuZGFib3QgYWxlcnRzPipcblxuIiArCiAgICAobWFwKAogICAgICAiYFwoLnBrZylgIChcKC5tYW5pZmVzdHMgfCBqb2luKCIsICIpKSkgXHUyMTkyIFVwZ3JhZGUgdG8gYFwoLmZpeClgXG4iICsKICAgICAgKC5jdmVzIHwgbWFwKCIgIFx1MjAyMiA8aHR0cHM6Ly9naXRodWIuY29tL2Fkdmlzb3JpZXMvXCguZ2hzYSl8XCguY3ZlKT4gKFwoLnNldmVyaXR5KSlcbiAgICBcKC5zdW1tYXJ5KSIpIHwgam9pbigiXG4iKSkKICAgICkgfCBqb2luKCJcblxuIikpICsKICAgICJcblxuKkFjdGlvbiBuZWVkZWQqOiBVcGdyYWRlIHRoZSBhZmZlY3RlZCBkZXBlbmRlbmN5IHZlcnNpb25zIHRvIHRoZSBmaXggdmVyc2lvbnMgbGlzdGVkIGFib3ZlLiIKICBlbmQK" shell: bash run: | ONE_DAY_AGO=$(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-24H +%Y-%m-%dT%H:%M:%SZ) @@ -66,3 +66,281 @@ jobs: echo "" echo "Slack notification sent." + + check-upstream-advisories: + if: github.repository == 'aws/aws-sdk-java-v2' + runs-on: ubuntu-latest + timeout-minutes: 3 + permissions: + contents: read + steps: + - uses: actions/checkout@v6 + with: + sparse-checkout: pom.xml + sparse-checkout-cone-mode: false + + - name: Check for new CVEs in upstream dependencies + env: + GH_TOKEN: ${{ secrets.DEPENDABOT_ALERTS_TOKEN }} + SLACK_WEBHOOK_URL: ${{ secrets.CI_SLACK_WEBHOOK_URL }} + shell: bash + run: | + set -euo pipefail + + ALERTS="" + NOW=$(date -u +%s) + # Check for CVEs published in the last 24 hours + ONE_DAY_AGO=$(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-24H +%Y-%m-%dT%H:%M:%SZ) + + # ============================================================ + # SDK versions from pom.xml + # ============================================================ + NETTY_VERSION=$(grep -oP '(?<=)[^<]+' pom.xml | sed 's/.Final//') + NETTY_PATCH=$(echo "$NETTY_VERSION" | grep -oP '\d+$') + NETTY_MAJOR_MINOR=$(echo "$NETTY_VERSION" | grep -oP '^\d+\.\d+') + + JACKSON_VERSION=$(grep -oP '(?<=)[^<]+' pom.xml) + JACKSON_DATABIND_VERSION=$(grep -oP '(?<=)[^<]+' pom.xml) + + HTTPCLIENT5_VERSION=$(grep -oP '(?<=)[^<]+' pom.xml) + HTTPCORE5_VERSION=$(grep -oP '(?<=)[^<]+' pom.xml) + + echo "SDK versions:" + echo " Netty: $NETTY_VERSION" + echo " Jackson: $JACKSON_VERSION (databind: $JACKSON_DATABIND_VERSION)" + echo " httpclient5: $HTTPCLIENT5_VERSION" + echo " httpcore5: $HTTPCORE5_VERSION" + + # ============================================================ + # NETTY: Check repo-level security advisories + # ============================================================ + echo "" + echo "=== Checking Netty repo advisories ===" + + SDK_NETTY_PACKAGES=( + "io.netty:netty-codec-http" + "io.netty:netty-codec-http2" + "io.netty:netty-codec" + "io.netty:netty-transport" + "io.netty:netty-transport-native-epoll" + "io.netty:netty-transport-classes-epoll" + "io.netty:netty-common" + "io.netty:netty-buffer" + "io.netty:netty-handler" + "io.netty:netty-resolver" + "io.netty:netty-resolver-dns" + ) + + NETTY_ADVISORIES=$(gh api "repos/netty/netty/security-advisories?sort=published&direction=desc&per_page=30") + + NETTY_NEW=$(echo "$NETTY_ADVISORIES" | jq --arg cutoff "$ONE_DAY_AGO" --arg major_minor "$NETTY_MAJOR_MINOR" --arg sdk_patch "$NETTY_PATCH" \ + --argjson sdk_packages "$(printf '%s\n' "${SDK_NETTY_PACKAGES[@]}" | jq -R . | jq -s .)" \ + '[.[] | + select(.published_at > $cutoff) | + select([.vulnerabilities[].package.name] | any(. as $pkg | $sdk_packages | index($pkg))) | + select(.vulnerabilities[] | + select(.package.name as $pkg | $sdk_packages | index($pkg)) | + (.patched_versions | capture("(?" + $major_minor + "\\.(?

[0-9]+))") | (.p | tonumber) > ($sdk_patch | tonumber)) + ) | + {ghsa_id, severity, summary, + patched: ([.vulnerabilities[] | select(.package.name as $pkg | $sdk_packages | index($pkg)) | .patched_versions | capture("(?" + $major_minor + "\\.(?

[0-9]+))").v] | max), + packages: [.vulnerabilities[] | select(.package.name as $pkg | $sdk_packages | index($pkg)) | .package.name] | unique} + ]') + + NETTY_COUNT=$(echo "$NETTY_NEW" | jq 'length') + echo "Found $NETTY_COUNT new Netty advisories affecting SDK (published in last 24h)" + + if [ "$NETTY_COUNT" -gt 0 ]; then + NETTY_MSG=$(echo "$NETTY_NEW" | jq -r ' + (map(.patched) | max) as $max_patched | + "⚠️ *" + (length | tostring) + " Netty CVE(s) detected via *\n\n" + + (map(" • (\(.severity | ascii_upcase)) — \(.packages | join(", "))\n \(.summary | split(". ") | first | if length > 150 then .[:147] + "..." else . end)") | join("\n")) + + "\n\n*Action needed*: Upgrade Netty from `'"$NETTY_VERSION"'.Final` → `" + $max_patched + ".Final`" + ') + ALERTS="${ALERTS}${NETTY_MSG}\n\n" + fi + + # ============================================================ + # JACKSON: Check repo-level security advisories + # ============================================================ + echo "" + echo "=== Checking Jackson repo advisories ===" + + JACKSON_ALERTS="" + for REPO in "FasterXML/jackson-databind" "FasterXML/jackson-core" "FasterXML/jackson-dataformats-binary"; do + PKG_NAME=$(echo "$REPO" | sed 's|FasterXML/||') + + if [ "$PKG_NAME" = "jackson-databind" ]; then + SDK_VER="$JACKSON_DATABIND_VERSION" + else + SDK_VER="$JACKSON_VERSION" + fi + + SDK_MINOR=$(echo "$SDK_VER" | grep -oP '^\d+\.\d+') + SDK_PATCH=$(echo "$SDK_VER" | grep -oP '\d+$') + + ADVISORIES=$(gh api "repos/$REPO/security-advisories?sort=published&direction=desc&per_page=10") + + NEW_ADVISORIES=$(echo "$ADVISORIES" | jq --arg cutoff "$ONE_DAY_AGO" --arg sdk_minor "$SDK_MINOR" --arg sdk_patch "$SDK_PATCH" --arg sdk_ver "$SDK_VER" \ + '[.[] | + select(.published_at > $cutoff) | + # Find vulnerabilities that match our version line AND where SDK is in the affected range + select([.vulnerabilities[] | + select(.package.name | startswith("com.fasterxml.jackson")) | + select(.patched_versions != null and .patched_versions != "") | + select(.vulnerable_version_range | test($sdk_minor)) | + select( + (.patched_versions // "") | + if . == "" then + false + else + capture("(?" + $sdk_minor + "\\.(?

[0-9]+))") | + (.p | tonumber) > ($sdk_patch | tonumber) + end + ) + ] | length > 0) | + { + ghsa_id, + severity, + summary, + patched: ([.vulnerabilities[] | + select(.package.name | startswith("com.fasterxml.jackson")) | + select(.patched_versions != null and .patched_versions != "") | + select(.vulnerable_version_range | test($sdk_minor)) | + .patched_versions // "" | + capture("(?" + $sdk_minor + "\\.(?

[0-9]+))").v // null + ] | map(select(. != null)) | max // "unknown") + } + ]') + + COUNT=$(echo "$NEW_ADVISORIES" | jq 'length') + echo " $REPO: $COUNT new advisories (last 24h, affecting SDK)" + + if [ "$COUNT" -gt 0 ]; then + MAX_PATCHED=$(echo "$NEW_ADVISORIES" | jq -r '[.[].patched] | map(select(. != "unknown")) | max // "latest"') + JACKSON_MSG=$(echo "$NEW_ADVISORIES" | jq -r --arg repo "$REPO" --arg max_patched "$MAX_PATCHED" ' + "⚠️ *" + (length | tostring) + " '"$PKG_NAME"' CVE(s) detected via *\n\n" + + (map(" • (\(.severity | ascii_upcase)) — \(.summary | split(". ") | first | if length > 150 then .[:147] + "..." else . end)") | join("\n")) + + "\n\n*Action needed*: Upgrade '"$PKG_NAME"' from `'"$SDK_VER"'` → `" + $max_patched + "`" + ') + ALERTS="${ALERTS}${JACKSON_MSG}\n\n" + fi + done + + # ============================================================ + # APACHE: Check NVD for new CVEs, get details from cve.org + # ============================================================ + echo "" + echo "=== Checking Apache httpcomponents via NVD ===" + + NVD_RESULTS=$(curl -s "https://services.nvd.nist.gov/rest/json/cves/2.0?keywordSearch=httpcomponents&pubStartDate=${ONE_DAY_AGO}&pubEndDate=$(date -u +%Y-%m-%dT%H:%M:%S.000)&resultsPerPage=10") + + APACHE_CVES=$(echo "$NVD_RESULTS" | jq -r '.vulnerabilities[]?.cve.id // empty') + + if [ -z "$APACHE_CVES" ]; then + echo " No new Apache httpcomponents CVEs in last 24h" + else + APACHE_ALERTS="" + APACHE_ACTION="" + while IFS= read -r CVE_ID; do + echo " Checking $CVE_ID..." + + # Get structured data from cve.org + CVE_DATA=$(curl -s "https://cveawg.mitre.org/api/cve/$CVE_ID") + + # Extract affected package and version + PACKAGE=$(echo "$CVE_DATA" | jq -r '.containers.cna.affected[0].packageName // .containers.cna.affected[0].product // "unknown"') + + # Check if this affects SDK's versions + AFFECTS_SDK=false + FIX_VERSION="" + DESCRIPTION_FULL=$(echo "$CVE_DATA" | jq -r '.containers.cna.descriptions[0].value // ""') + DESCRIPTION=$(echo "$DESCRIPTION_FULL" | tr '\n' ' ' | sed 's/ */ /g' | sed 's/\. /.\n/' | head -1) + if [ ${#DESCRIPTION} -gt 150 ]; then + DESCRIPTION="${DESCRIPTION:0:147}..." + fi + + # Try to extract fix version from description + FIX_FROM_DESC=$(echo "$DESCRIPTION_FULL" | grep -oP 'upgrade to (?:at least )?version \K[0-9.]+' || echo "") + + # Determine SDK current version based on package + SDK_CURRENT="" + if echo "$PACKAGE" | grep -q "httpclient5"; then + SDK_CURRENT="$HTTPCLIENT5_VERSION" + elif echo "$PACKAGE" | grep -q "httpcore5"; then + SDK_CURRENT="$HTTPCORE5_VERSION" + else + continue + fi + + # Check ALL version entries — SDK is affected if its version <= lessThanOrEqual or < lessThan + VERSIONS_COUNT=$(echo "$CVE_DATA" | jq '.containers.cna.affected[0].versions | length') + SDK_MAJOR_MINOR_APACHE=$(echo "$SDK_CURRENT" | sed 's/\.[0-9]*$//') + for i in $(seq 0 $((VERSIONS_COUNT - 1))); do + LESS_THAN=$(echo "$CVE_DATA" | jq -r ".containers.cna.affected[0].versions[$i].lessThan // \"\"") + LESS_THAN_EQ=$(echo "$CVE_DATA" | jq -r ".containers.cna.affected[0].versions[$i].lessThanOrEqual // \"\"") + VER_BOUND="${LESS_THAN_EQ:-$LESS_THAN}" + + # Skip entries for different version lines (alpha/beta entries that don't match our major.minor) + if echo "$VER_BOUND" | grep -q "alpha\|beta"; then + continue + fi + + # Skip if the bound doesn't start with our major.minor + if ! echo "$VER_BOUND" | grep -q "^${SDK_MAJOR_MINOR_APACHE}\."; then + continue + fi + + if [ -n "$LESS_THAN" ]; then + # Affected if SDK_CURRENT < LESS_THAN + if [ "$(printf '%s\n' "$SDK_CURRENT" "$LESS_THAN" | sort -V | head -1)" = "$SDK_CURRENT" ] && [ "$SDK_CURRENT" != "$LESS_THAN" ]; then + AFFECTS_SDK=true + FIX_VERSION="${FIX_FROM_DESC:-$LESS_THAN}" + break + fi + elif [ -n "$LESS_THAN_EQ" ]; then + # Affected if SDK_CURRENT <= LESS_THAN_EQ + if [ "$(printf '%s\n' "$SDK_CURRENT" "$LESS_THAN_EQ" | sort -V | head -1)" = "$SDK_CURRENT" ]; then + AFFECTS_SDK=true + FIX_VERSION="${FIX_FROM_DESC:-"> $LESS_THAN_EQ"}" + break + fi + fi + done + + if [ "$AFFECTS_SDK" = true ]; then + APACHE_ALERTS="${APACHE_ALERTS} • — $PACKAGE\n $DESCRIPTION\n" + APACHE_ACTION="*Action needed*: Upgrade \`$PACKAGE\` from \`$SDK_CURRENT\` → \`$FIX_VERSION\`" + fi + done <<< "$APACHE_CVES" + + if [ -n "$APACHE_ALERTS" ]; then + APACHE_COUNT=$(echo -e "$APACHE_ALERTS" | grep -c "•") + APACHE_MSG="⚠️ *${APACHE_COUNT} Apache HttpComponents CVE(s) detected via *\n\n${APACHE_ALERTS}\n${APACHE_ACTION}" + ALERTS="${ALERTS}${APACHE_MSG}\n\n" + fi + fi + + # ============================================================ + # Send Slack notification if any alerts found + # ============================================================ + echo "" + if [ -z "$ALERTS" ]; then + echo "No new CVEs found across all upstream sources." + exit 0 + fi + + echo "Sending Slack notification..." + FINAL_MESSAGE=$(echo -e "$ALERTS") + echo "$FINAL_MESSAGE" + + if [ -n "$SLACK_WEBHOOK_URL" ]; then + PAYLOAD=$(jq -n --arg text "$FINAL_MESSAGE" '{text: $text}') + curl -s -X POST "$SLACK_WEBHOOK_URL" \ + -H 'Content-Type: application/json' \ + -d "$PAYLOAD" + echo "" + echo "Slack notification sent." + else + echo "No SLACK_WEBHOOK_URL configured. Skipping notification." + fi