Integrations

Get new tickets into Slack, or anything else that reads RSS or JSON. No account and no sign-up: you fetch public URLs, and pwned.coffee never asks for yours.

The URLs

Polling politely

feed.xml, incidents.json and changes.json send a weak ETag and answer 304 Not Modified to a matching If-None-Match. The tag follows the content, not the time it was generated. A relative span such as since=35m is rounded to the minute, so its tag can change from one minute to the next; for a cheap poll, pass the next_since from your last response back as since. A timestamp is taken exactly, so nothing comes back twice.

Agents can use the MCP server instead: diff_since and whats_new answer the same question.

Slack through Make

  1. Add RSS › Watch RSS feed items with the URL https://pwned.coffee/feed.xml?stack=your,stack,ids.
  2. Add a filter: the item's categories contain CISA KEV.
  3. Add Slack › Create a message with the item's title and link.

Module and field names are as Make labels them today and may differ in your account.

Limit: a ticket that becomes KEV after it was listed won't appear as a new item.

Repeats. The feed is hottest first, not newest first, and each item's guid is the ticket id plus its updated_at, so a ticket that is corrected can come back as a new item. How Make's RSS trigger de-duplicates a feed like this isn't something we have verified. If you see repeats, use the HTTP + changes.json recipe below.

Slack without Make: GitHub Actions

This runs in your repo; pwned.coffee never sees or stores your webhook.

  1. Create an incoming webhook for your Slack channel: Slack's guide. Keep the URL secret.
  2. In your repo, add it as the Actions secret SLACK_WEBHOOK_URL (Settings › Secrets and variables › Actions).
  3. Save this as .github/workflows/pwned-coffee-slack.yml:
name: pwned.coffee to Slack
on:
  schedule:
    - cron: '*/30 * * * *'
  workflow_dispatch:
permissions: {}
jobs:
  post:
    runs-on: ubuntu-latest
    steps:
      - name: Post new KEV tickets to Slack
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
        run: |
          set -euo pipefail
          curl -fsS --max-time 30 "https://pwned.coffee/changes.json?since=35m" -o changes.json
          text=$(jq -r 'def esc: gsub("&";"&amp;") | gsub("<";"&lt;") | gsub(">";"&gt;") | gsub("\\|";"/");
            [(.new_tickets // [])[] | select(.exploitation == "kev") | "• [\(.severity)] <\(.url)|\(.title | esc)>"] | join("\n")' changes.json)
          if [ -z "$text" ]; then echo "No new KEV tickets in the last 35 minutes"; exit 0; fi
          jq -n --arg text "$text" '{text: $text}' | curl -fsS --max-time 30 -X POST -H 'Content-type: application/json' --data @- "$SLACK_WEBHOOK_URL"

Not security advice. Confirm against the vendor advisory linked on each ticket.