README
¶
JSMon-Go
JavaScript Change Monitor for Bug Bounty Hunting
A high-performance Go rewrite of the original JSMon Python tool. Monitor JavaScript files on websites and get notified when they change, helping you discover new attack surfaces and vulnerabilities during bug bounty hunting.
Features • Installation • Quick Start • Documentation • Docker
Features
- 🚀 Single Binary - No Python runtime or dependencies needed
- ⚡ 10x Faster - Concurrent fetching with goroutines vs sequential Python
- 🔄 Retry Logic - Automatic retry with exponential backoff for failed requests
- 📊 Beautiful HTML Diffs - Beautified JavaScript with side-by-side comparison
- 🔔 Multi-Channel Notifications - Telegram, Slack, and Discord support
- 🐛 Bug Fixes - Resolves Discord webhook bug from original Python version
- 🏗️ Better Architecture - Clean, modular codebase with proper error handling
- 📦 Easy Distribution - Cross-compile for Linux, macOS, Windows, and Docker
- 🔒 Minimal Attack Surface - Distroless Docker images for security
Why Go?
| Feature | Python Version | Go Version |
|---|---|---|
| Execution | Interpreted (~500ms startup) | Compiled (~10ms startup) |
| Concurrency | Sequential | Parallel (goroutines) |
| Binary Size | N/A (requires runtime) | 8.9MB (includes everything) |
| Memory | ~50-100MB | ~10-20MB |
| Speed (100 endpoints) | ~100s | ~10s (10x faster) |
| Dependencies | pip packages + venv | Embedded in binary |
| Discord Bug | Present | Fixed ✅ |
Quick Start
# Download and extract binary (Linux amd64 example)
VERSION=1.0.0 # Check https://github.com/LuD1161/jsmon-go/releases for latest
curl -L https://github.com/LuD1161/jsmon-go/releases/download/v${VERSION}/jsmon-go_${VERSION}_Linux_x86_64.tar.gz | tar xz
sudo mv jsmon /usr/local/bin/jsmon
# Create configuration
cat > .env << EOF
JSMON_NOTIFY_TELEGRAM=true
JSMON_TELEGRAM_TOKEN=your_bot_token
JSMON_TELEGRAM_CHAT_ID=your_chat_id
EOF
# Add targets to monitor
mkdir targets
cat > targets/my-targets << EOF
https://example.com/static/js/app.js
https://example.com/static/js/bundle.js
EOF
# Run (first run enrolls endpoints without notifications)
jsmon
# Run again to detect changes
jsmon
Installation
Option 1: Docker (Recommended for Production)
# Pull the image
docker pull ghcr.io/LuD1161/jsmon-go:latest
# Run with mounted volumes
docker run --rm \
-v $(pwd)/targets:/app/targets \
-v $(pwd)/downloads:/app/downloads \
-v $(pwd)/jsmon.json:/app/jsmon.json \
-v $(pwd)/.env:/app/.env \
ghcr.io/LuD1161/jsmon-go:latest
Option 2: Pre-built Binary
Download the latest release for your platform from the Releases page.
Note: Replace VERSION with the latest version (e.g., 1.0.0) from the releases page.
Linux:
# amd64
VERSION=1.0.0
curl -L https://github.com/LuD1161/jsmon-go/releases/download/v${VERSION}/jsmon-go_${VERSION}_Linux_x86_64.tar.gz | tar xz
sudo mv jsmon /usr/local/bin/jsmon
# arm64
VERSION=1.0.0
curl -L https://github.com/LuD1161/jsmon-go/releases/download/v${VERSION}/jsmon-go_${VERSION}_Linux_arm64.tar.gz | tar xz
sudo mv jsmon /usr/local/bin/jsmon
macOS:
# Apple Silicon (M1/M2/M3)
VERSION=1.0.0
curl -L https://github.com/LuD1161/jsmon-go/releases/download/v${VERSION}/jsmon-go_${VERSION}_Darwin_arm64.tar.gz | tar xz
sudo mv jsmon /usr/local/bin/jsmon
# Intel
VERSION=1.0.0
curl -L https://github.com/LuD1161/jsmon-go/releases/download/v${VERSION}/jsmon-go_${VERSION}_Darwin_x86_64.tar.gz | tar xz
sudo mv jsmon /usr/local/bin/jsmon
Windows:
# Download and extract (replace 1.0.0 with latest version)
$VERSION = "1.0.0"
curl -L -o jsmon-go.zip "https://github.com/LuD1161/jsmon-go/releases/download/v$VERSION/jsmon-go_${VERSION}_Windows_x86_64.zip"
Expand-Archive jsmon-go.zip -DestinationPath .
# Move jsmon.exe to a directory in your PATH
Option 3: Build from Source
# Clone the repository
git clone https://github.com/LuD1161/jsmon-go.git
cd jsmon-go
# Build for current platform
make build
# Or install to GOPATH/bin
make install
# Or build for all platforms
make build-all
Option 4: Go Install
go install github.com/LuD1161/jsmon-go/cmd/jsmon@latest
Configuration
Create a .env file in your working directory:
# Telegram (Recommended - easiest to set up)
JSMON_NOTIFY_TELEGRAM=true
JSMON_TELEGRAM_TOKEN=your_bot_token_here
JSMON_TELEGRAM_CHAT_ID=your_chat_id_here
# Slack
JSMON_NOTIFY_SLACK=false
JSMON_SLACK_TOKEN=xoxb-your-token
JSMON_SLACK_CHANNEL_ID=C01234567
# Discord
JSMON_NOTIFY_DISCORD=false
JSMON_DISCORD_WEBHOOK=https://discord.com/api/webhooks/...
Getting Notification Credentials
Telegram (Easiest - Recommended)
- Message @BotFather and create a bot with
/newbot - Copy the token provided
- Message your bot with any text
- Visit
https://api.telegram.org/bot<YOUR_TOKEN>/getUpdatesto get yourchat_id - Add both values to your
.envfile
Slack
- Create a Slack App at https://api.slack.com/apps
- Add
files:writeandchat:writepermissions - Install to your workspace
- Copy the OAuth token (starts with
xoxb-) - Get your channel ID from channel details (right-click channel → View channel details)
Discord
- Go to Server Settings → Integrations → Webhooks
- Create a new webhook
- Copy the webhook URL
- Add to your
.envfile
Usage
Adding Targets
Create files in the targets/ directory with one URL per line:
mkdir targets
# Add endpoints to monitor
cat > targets/example-site << EOF
# Main application bundle
https://example.com/static/js/app.js
https://example.com/static/js/bundle.js
# CDN resources
https://cdn.example.com/scripts/main.js
EOF
# Organize by program/site
cat > targets/hackerone-program << EOF
https://target.example.com/assets/application.js
https://target.example.com/webpack/vendor.js
EOF
Notes:
- Lines starting with
#are treated as comments - Empty lines are ignored
- You can organize targets across multiple files
Running JSMon
# Run once
jsmon
# With custom working directory
cd /path/to/monitoring && jsmon
First run: All endpoints are enrolled without sending notifications.
Subsequent runs: Changes are detected and notifications sent with beautified HTML diff attachments.
Example Output
JSMon - Web File Monitor (Go Edition)
Monitoring 5 endpoint(s)...
✓ Telegram notifications enabled
No change: https://example.com/app.js
⚠ Change detected: https://example.com/bundle.js (abc123def4 → xyz789ghi0)
✓ Notification sent
⊕ New endpoint enrolled: https://example.com/new.js
✗ Failed to fetch https://down.example.com/app.js: connection timeout
==================================================
Summary: 5 endpoints monitored
• 1 new endpoint(s) enrolled
• 1 change(s) detected and notified
• 1 error(s) occurred
Automated Monitoring
Cron (Linux/macOS):
# Edit crontab
crontab -e
# Run every hour
0 * * * * cd /path/to/jsmon && /usr/local/bin/jsmon >> /var/log/jsmon.log 2>&1
# Run every 6 hours
0 */6 * * * cd /path/to/jsmon && /usr/local/bin/jsmon >> /var/log/jsmon.log 2>&1
Systemd Timer (Linux):
# /etc/systemd/system/jsmon.timer
[Unit]
Description=JSMon Change Monitor
[Timer]
OnCalendar=hourly
Persistent=true
[Install]
WantedBy=timers.target
Docker Compose + Cron:
version: '3.8'
services:
jsmon:
image: ghcr.io/LuD1161/jsmon-go:latest
volumes:
- ./targets:/app/targets
- ./downloads:/app/downloads
- ./jsmon.json:/app/jsmon.json
- ./.env:/app/.env
restart: "no"
Then run via cron:
0 * * * * cd /path/to/jsmon && docker-compose run --rm jsmon
Docker
Using Pre-built Images
# Pull the latest image
docker pull ghcr.io/LuD1161/jsmon-go:latest
# Or a specific version
docker pull ghcr.io/LuD1161/jsmon-go:v1.0.0
# Run with mounted volumes
docker run --rm \
-v $(pwd)/targets:/app/targets \
-v $(pwd)/downloads:/app/downloads \
-v $(pwd)/jsmon.json:/app/jsmon.json \
-v $(pwd)/.env:/app/.env \
ghcr.io/LuD1161/jsmon-go:latest
Building Locally
# Build the image from source (uses Dockerfile.standalone)
docker build -f Dockerfile.standalone -t jsmon-go .
# Run it
docker run --rm \
-v $(pwd)/targets:/app/targets \
-v $(pwd)/downloads:/app/downloads \
-v $(pwd)/jsmon.json:/app/jsmon.json \
-v $(pwd)/.env:/app/.env \
jsmon-go
Note: The default Dockerfile is optimized for GoReleaser (expects pre-built binary). For building from source, use Dockerfile.standalone.
Why Distroless?
The Docker image uses Google's distroless base image:
- Security: No shell, no package manager - minimal attack surface
- Size: ~20MB total (vs ~100MB+ with Alpine)
- Performance: Only includes runtime dependencies
How It Works
┌─────────────┐
│ targets/ │ Load endpoint URLs
└──────┬──────┘
│
▼
┌─────────────────────────────┐
│ Concurrent HTTP Fetching │ Goroutines + retry logic
│ (with exponential backoff) │
└──────────┬──────────────────┘
│
▼
┌──────────────┐
│ MD5 Hashing │ 10-char truncated hash
└──────┬───────┘
│
▼
┌─────────────────┐
│ Compare to State│ Check jsmon.json
│ (jsmon.json) │
└────────┬────────┘
│
┌────┴─────┐
│ │
▼ ▼
No Change Changed!
│ │
│ ▼
│ ┌──────────────┐
│ │ Beautify JS │
│ │ Generate Diff│
│ └──────┬───────┘
│ │
│ ▼
│ ┌─────────────────────┐
│ │ Send Notifications │
│ │ (Telegram/Slack/ │
│ │ Discord) │
│ └─────────────────────┘
│
└──────────┬──────────────┘
│
▼
┌──────────────┐
│ Save State │
│ & Content │
└──────────────┘
Development
# Install dependencies
make deps
# Build for current platform
make build
# Run tests
make test
# Build for all platforms (Linux, macOS, Windows)
make build-all
# Clean build artifacts
make clean
# Show all available targets
make help
Project Structure
jsmon-go/
├── cmd/
│ └── jsmon/
│ └── main.go # Application entry point
├── internal/ # Private packages
│ ├── config/ # Environment configuration
│ │ └── config.go # .env loading & validation
│ ├── storage/ # State management
│ │ └── storage.go # jsmon.json & downloads/
│ ├── fetcher/ # HTTP operations
│ │ └── fetcher.go # Concurrent fetching + retry
│ ├── differ/ # Diff generation
│ │ └── differ.go # JS beautification + HTML diff
│ └── notifier/ # Notifications
│ ├── notifier.go # Interface
│ ├── telegram.go # Telegram API
│ ├── slack.go # Slack API
│ └── discord.go # Discord webhooks
├── Dockerfile # Distroless container image
├── .goreleaser.yml # Release automation
├── Makefile # Build automation
├── go.mod # Go dependencies
└── README.md
Performance Comparison
Scenario: Monitoring 100 JavaScript endpoints
| Metric | Python | Go | Improvement |
|---|---|---|---|
| Execution Time | ~100s | ~10s | 10x faster |
| Memory Usage | ~80MB | ~15MB | 5x less |
| Binary Size | N/A | 8.9MB | Portable |
| Cold Start | ~500ms | ~10ms | 50x faster |
| Concurrent Requests | No | Yes | ✅ |
| Retry Logic | No | Yes | ✅ |
Improvements Over Python Version
Fixed Bugs
- ✅ Discord webhook actually uses the webhook URL (was hardcoded string
"DISCORD_WEBHOOK_URL") - ✅ Proper error handling - failed endpoints don't stop entire run
- ✅ Configuration validation before execution
New Features
- ✅ Concurrent fetching with goroutines (10x faster for many targets)
- ✅ Retry logic with exponential backoff (3 retries, 30s timeout)
- ✅ Better progress output with status symbols (✓, ✗, ⊕, ⚠)
- ✅ Single binary distribution - no runtime dependencies
- ✅ Cross-platform builds - Linux, macOS, Windows, Docker
- ✅ Docker support with minimal distroless images
Better Architecture
- ✅ Clean separation of concerns - config, storage, fetcher, differ, notifier
- ✅ Interface-based design - easy to test and extend
- ✅ Type safety - compile-time error checking
- ✅ Proper error propagation throughout the stack
Contributing
Contributions are welcome! Here's how you can help:
Reporting Bugs
- Check existing issues
- Create a new issue with detailed reproduction steps
- Include your OS, Go version, and JSMon version
Suggesting Features
- Open an issue with the
enhancementlabel - Describe the use case and expected behavior
- Be open to discussion and feedback
Submitting Pull Requests
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests:
make test - Commit with clear messages
- Push to your fork
- Open a Pull Request with a detailed description
Development Setup
git clone https://github.com/LuD1161/jsmon-go.git
cd jsmon-go
make deps
make build
Credits
This is a Go rewrite of the original Python JSMon by @r0bre.
Original Contributors
- @r0bre - Core Python version
- @Yassineaboukir - Slack notifications
- @seczq - Discord notifications
License
MIT License - See LICENSE file for details.
Security & Responsible Use
⚠️ Important: This tool is designed for authorized security testing and bug bounty hunting only.
- Ensure you have permission to monitor the targets you configure
- Respect rate limits and avoid overwhelming servers
- Follow responsible disclosure practices
- Comply with bug bounty program rules
- Don't use for unauthorized access or malicious purposes
Support
Built with ❤️ for the bug bounty community