Skip to content
Open
Show file tree
Hide file tree
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
33 changes: 33 additions & 0 deletions webhook-server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
Setup and testing for the sample Facebook Messenger webhook

1) Install and run the server
cd webhook-server
npm init -y
npm install express body-parser
n # set a verify token and (optionally) PAGE_ACCESS_TOKEN
set VERIFY_TOKEN=your_verify_token_here # Windows PowerShell: $env:VERIFY_TOKEN = "..."
set PAGE_ACCESS_TOKEN=your_page_access_token_here
Comment on lines +8 to +9

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use shell-specific environment-variable commands.

Line 9 uses Command Prompt syntax. PowerShell users will not set PAGE_ACCESS_TOKEN. Show separate commands for Command Prompt, PowerShell, and POSIX shells.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@webhook-server/README.md` around lines 8 - 9, Update the environment-variable
setup instructions in the README to provide separate commands for Command
Prompt, PowerShell, and POSIX shells, ensuring PAGE_ACCESS_TOKEN and
VERIFY_TOKEN use syntax valid for each shell.


node server.js

2) Expose locally with ngrok (HTTPS required by Facebook)
ngrok http 3000
# copy the https URL (e.g. https://abcd1234.ngrok.io)

3) Configure the App (developers.facebook.com)
- My Apps → Create App (choose Business or appropriate type)
- App Dashboard → Add Product → Messenger → Set up
- Under Webhooks: Callback URL = https://<NGROK_HOST>/webhook
Verify token = the same VERIFY_TOKEN you set
- Subscribe to fields: messages, messaging_postbacks, messaging_optins, message_deliveries

4) Subscribe your Page to the app
Using Graph API (replace PAGE_ID and PAGE_ACCESS_TOKEN):
curl -X POST "https://graph.facebook.com/v17.0/PAGE_ID/subscribed_apps?access_token=PAGE_ACCESS_TOKEN"
Comment on lines +25 to +26

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

On the official Meta Graph API versioning documentation, is Graph API v17.0supported on August 5, 2026? Which supported Graph API version should be used for the/{page-id}/subscribed_apps endpoint?

💡 Result:

On the official Meta Graph API documentation, Graph API v17.0 is not supported on August 5, 2026. According to the Meta Graph API changelog, v17.0 reached its end-of-life on September 12, 2025 [1][2][3]. For the /{page-id}/subscribed_apps endpoint, you should use the latest supported Graph API version, which is currently v26.0 [1][4][5]. Meta recommends using the most recent version to ensure access to the latest features and security updates [6][7].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== repository files matching webhook-server/README.md =="
git ls-files | grep -F 'webhook-server/README.md' || true

echo
echo "== current webhook-server/README.md lines 18-32 =="
sed -n '18,32p' webhook-server/README.md | cat -n

echo
echo "== Graph API version mentions in webhook-server =="
rg -n "graph\.facebook\.com|subscribed_apps|api-version|api version|Graph API version|v17\.0|v26\.0" webhook-server || true

Repository: f/prompts.chat

Length of output: 1422


Use a supported Graph API version in the subscription command.

v17.0 reached end-of-life outside the current supported range. Update the curl example to a supported version such as v26.0 and document the Graph API version maintenance requirement.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@webhook-server/README.md` around lines 25 - 26, Update the Graph API version
in the README subscription curl example to a currently supported version such as
v26.0, and add a brief note documenting that this version must be maintained as
Facebook’s supported API range changes.


5) Notes
- In development mode the app only receives events for Pages where the app admin/tester is added.
- To receive events from real users you must submit for App Review and switch the app live.
- Implement Send API calls using the PAGE_ACCESS_TOKEN to reply to users.

If you want, update the server to send replies (I can add Send API example and a .env + npm scripts).
Expand Down
46 changes: 46 additions & 0 deletions webhook-server/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Simple Facebook Messenger webhook server (Express)
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());

const VERIFY_TOKEN = process.env.VERIFY_TOKEN || 'verify_token_here';

// Webhook verification handshake
app.get('/webhook', (req, res) => {
const mode = req.query['hub.mode'];
const token = req.query['hub.verify_token'];
const challenge = req.query['hub.challenge'];

if (mode === 'subscribe' && token === VERIFY_TOKEN) {
return res.status(200).send(challenge);
}
return res.sendStatus(403);
});

// Webhook event receiver
app.post('/webhook', (req, res) => {
console.log('Webhook event:', JSON.stringify(req.body, null, 2));
n // Basic handling: iterate entries and messaging events
if (req.body.object === 'page') {
Comment on lines +22 to +25

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Remove the stray n before the event handler logic.

Line 24 evaluates n as an identifier. Every POST request then throws ReferenceError before the handler can return HTTP 200.

- n  // Basic handling: iterate entries and messaging events
+ // Basic handling: iterate entries and messaging events
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
app.post('/webhook', (req, res) => {
console.log('Webhook event:', JSON.stringify(req.body, null, 2));
n // Basic handling: iterate entries and messaging events
if (req.body.object === 'page') {
app.post('/webhook', (req, res) => {
console.log('Webhook event:', JSON.stringify(req.body, null, 2));
// Basic handling: iterate entries and messaging events
if (req.body.object === 'page') {
🧰 Tools
🪛 ast-grep (0.45.0)

[warning] 22-22: Logging request-derived input unsanitized allows log forging (CRLF injection); strip newlines / encode the value before logging.
Context: console.log('Webhook event:', JSON.stringify(req.body, null, 2))
Note: [CWE-117] Improper Output Neutralization for Logs. OWASP A09:2021 Security Logging and Monitoring Failures.

(log-injection-javascript)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@webhook-server/server.js` around lines 22 - 25, Remove the stray standalone n
before the webhook event-handling comment inside the /webhook POST handler,
ensuring the handler proceeds from the console.log call to the req.body.object
check without evaluating an undefined identifier.

req.body.entry.forEach(entry => {
const events = entry.messaging || [];
events.forEach(event => {
if (event.message) {
const senderId = event.sender.id;
const text = event.message.text;
console.log(`Message from ${senderId}: ${text}`);
// TODO: reply using Send API with PAGE_ACCESS_TOKEN
} else if (event.postback) {
console.log('Postback:', event.postback);
Comment on lines +29 to +35

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- file excerpt ---\n'
sed -n '1,80p' webhook-server/server.js

printf '\n--- relevant logging patterns ---\n'
rg -n "console\\.(log|error|warn|info)|senderId|event\\.message|event\\.sender" webhook-server/server.js

printf '\n--- deterministic newline-injection probes ---\n'
node - <<'JS'
const senderId = 'ALICE\n[BOT] MALICE: injected line';
const text = 'ok\n[YOUR MESSAGE] forged entry';
console.log(`Message from ${senderId}: ${text}`);
JS

Repository: f/prompts.chat

Length of output: 243


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- file excerpt ---'
sed -n '1,80p' webhook-server/server.js

echo
echo '--- relevant logging patterns ---'
rg -n "console\\.|senderId|event\\.message|event\\.sender" webhook-server/server.js || true

echo
echo '--- deterministic newline-injection probes ---'
node - <<'JS'
const senderId = 'ALICE\n[BOT] MALICE: injected line';
const text = 'ok\n[YOUR MESSAGE] forged entry';
console.log(`Message from ${senderId}: ${text}`);
JS

Repository: f/prompts.chat

Length of output: 2265


Log Injection (CWE-117)

Reachability: External · Exploitability: Trivial

Encode sender-controlled data before logging.

console.log includes event.sender.id and event.message.text directly, so newline characters can create forged or fragmented log entries. Serialize each field with JSON.stringify or use structured logging before writing it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@webhook-server/server.js` around lines 29 - 35, Update the message logging in
the event.message branch to serialize the senderId and text values before
passing them to console.log, using JSON.stringify or equivalent structured
logging. Preserve the existing log context and behavior while preventing
sender-controlled newlines from creating forged log entries.

Source: Linters/SAST tools

}
});
});
}

// Must respond 200 quickly
res.sendStatus(200);
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Webhook server listening on port ${PORT}`));
Expand Down