Hackly

Authorized attack-surface
scanning — with ownership gates.

Inventory targets you own, verify DNS ownership, scan linked GitHub repositories (Laravel/PHP-focused SAST & SCA), and review findings from a Filament admin panel. Built with Laravel 13 and Filament 5.

Coverage

Targets and repos.
Same control plane.

DAST for verified targets, SAST/SCA for GitHub clones — with soft rate limits on live probes and Aikido-style post-processing on repo findings.

Target scanners

01 DNS / WHOIS dig + whois — records, registrar, and basic exposure. quick · standard · deep
02 Port scan nmap top ports with light service detection. quick · standard · deep
03 Tech fingerprint Soft HTTP checks for PHP/Laravel headers, cookies, and debug pages. quick · standard · deep
04 Subdomains Soft wordlist + Certificate Transparency logs. standard · deep
05 Path discovery Soft wordlist / Nuclei — Laravel exposures (.env, Telescope, Horizon…). standard · deep
06 Nuclei templates OWASP + PHP/Laravel/dotenv vulnerability templates via nuclei. standard · deep
07 OWASP ZAP DAST Baseline DAST for deep profile — longer timeout, cooldown enforced. deep

Repository scanners

Clone via PAT → run profile tasks → dedupe, PHP reachability, and noise filters.

01 Semgrep SAST PHP ruleset (p/php) on the shallow clone. standard · deep
02 Trivy SCA Dependency vulnerabilities from lockfiles and images. standard · deep
03 Gitleaks Secret detection across the repository history snapshot. quick · standard · deep
04 Checkov IaC Docker / Terraform / GitHub Actions — skipped when none present. deep
05 Composer + OSV composer audit and OSV CVE lookup when composer.lock exists. quick · standard · deep
06 Laravel PHP audit Committed .env, debug packages, Telescope/Horizon hints, mass-assignment risks. quick · standard · deep
07 Laravel live pentest HTTP probes on linked Targets when “Include linked targets”. standard · deep

Install

Up in minutes.

PHP 8.3+, Composer, and SQLite (or MySQL / PostgreSQL). A queue worker must be running for scans to execute.

Terminal — bootstrap
composer install
cp .env.example .env
php artisan key:generate
touch database/database.sqlite
php artisan migrate --seed
Terminal — run
# serve + queue + logs + vite
composer run dev

# or separately:
php artisan serve
php artisan queue:work  # required
php artisan schedule:work  # optional: cleanup only
01

Open the app

Visit / — seeded as admin@hackly.test / password. Change it immediately.

02

Add a target or a repo

Verify a domain via DNS TXT — and/or add a GitHub PAT, then register owner/repo.

03

Scan independently

Target DAST, repo SAST/SCA, or both via linked Targets ↔ Repositories. Findings sort HIGH → LOW.

Documentation

Reference

Dual-path architecture (targets + repos), profiles, CLI, env knobs, and the ownership-first security model.

Overview

Hackly is an orchestration layer for authorized attack-surface and application security scanning. You inventory targets, prove ownership, scan GitHub repositories via PAT, run soft rate-limited jobs, and review normalized findings in Filament.

Architecture
Target (verified)                    Repository (GitHub PAT)
   │                                      │
   ├─ optional link ──────────────────────┤
   │                                      │
   ├─ Scan (DAST)                         ├─ RepoScan
   │    └─ ScanTasks → Findings           │    └─ RepoScanTasks → Findings
   │                                      │         (asset_id nullable)
   └─ optional: include linked repos      └─ optional: include linked targets

Jobs use the database queue (no Horizon). A queue worker must be running for scans to execute. Linking Targets ↔ Repositories is optional — each side can scan on its own.

Requirements

  • PHP 8.3+
  • Composer
  • SQLite (default) or MySQL / PostgreSQL
  • git (for repository clones)
  • Node.js (optional — Vite assets; Filament ships published assets)
Default admin after seed: / · admin@hackly.test · password

Scanner binaries

Target scanners

Optional but recommended. Without them, related tasks fail gracefully and surface missing-binary errors in the scan UI.

Binary Used for
dig, whois DNS / WHOIS
nmap Ports
nuclei Templates & path discovery
zap.sh Deep DAST (OWASP ZAP)
Ubuntu — target tools
sudo bash scripts/install-scanner-binaries-ubuntu.sh
php artisan hackly:check-binaries

Repository scanners

Needed for GitHub repo scanning. Missing tools cause those tasks to be skipped (other tasks still run). Composer/OSV and Hackly Laravel auditors do not require Semgrep/Trivy.

Binary Used for
semgrep PHP SAST
trivy SCA
gitleaks Secrets
checkov IaC
composer composer audit
Ubuntu — repo tools
sudo bash scripts/install-repo-scanners.sh
php artisan hackly:check-binaries
Run hackly:check-binaries as the queue worker user (e.g. www-data). The install script puts tools on /usr/local/bin so they are not trapped in a root-only ~/.local.

Targets

Admin UI

  1. Open Targets → create a domain or IP
  2. Copy the DNS token → publish the TXT record at your DNS provider
  3. Verify DNS — must succeed before target scanning
  4. Start scan — pick a profile; optionally enable Include linked repositories
  5. Watch Scans for live progress, open findings (HIGH → LOW), export the PDF
  6. On a target’s detail page: Linked repositories + Scans

Targets do not need a linked repository.

CLI

Terminal
php artisan hackly:scan example.com --profile=standard
php artisan hackly:scan example.com --include-repos

Repositories

Admin UI

  1. Open GitHub tokens → add a PAT → Validate
  2. Open Repositories → add owner/repo (checked against the GitHub API)
  3. Optionally link one or more Targets
  4. Scan now — pick a repo profile; optionally Include linked targets (queues deep DAST on each verified linked Target)
  5. Review Repo scans and Findings on the repository page

Repo findings are stored on the repository (asset_id may be null). PDF export is for target scans only.

GitHub token permissions

Type Permission
Classic PAT repo (private) or public_repo (public only)
Fine-grained Contents: Read + Metadata: Read on selected repos

Post-processing

  • Cross-tool deduplication (e.g. same package + CVE from Trivy and OSV → one finding)
  • PHP reachability: namespace usage in app/, routes/, config/; require-dev → unreachable; Laravel package auto-discovery
  • Noise filters: placeholder secrets, path out of app scope, configurable rule suppressions
  • Findings store reachability, confidence, noise_filtered, and tools[]

CLI

Terminal
php artisan hackly:repo-scan owner/repo --profile=standard
php artisan hackly:repo-scan owner/repo --include-targets

Independent scan modes

Goal UI CLI
Target only Start scan (toggle off) hackly:scan example.com
Target + repos Include linked repositories hackly:scan … --include-repos
Repo only Scan now (toggle off) hackly:repo-scan owner/repo
Repo + targets Include linked targets hackly:repo-scan … --include-targets

Laravel live pentest runs only when the repo scan includes linked targets. Repo-only scans skip it.

Scan profiles

Target (DAST)

Profile Tasks
quick dns_info, port_scan, tech_fingerprint
standard + subdomain_enum, path_discovery, nuclei_owasp
deep + zap_baseline (cooldown between deep runs on the same target)

Repository (SAST / SCA)

Profile Tasks
quick gitleaks_secrets, composer_osv, laravel_php_audit
standard + semgrep_sast, trivy_sca, laravel_live_pentest*
deep + checkov_iac

* Live pentest only when linked targets are included. Findings are normalized to LOW / MEDIUM / HIGH.

Commands

Scans are started manually from the admin UI or CLI — there is no automatic hourly/nightly scan schedule.

Command Purpose
hackly:check-binaries Verify target + repo scanner binaries
hackly:scan {target} Target scan (--profile=, --include-repos)
hackly:repo-scan {repo} Repo scan (--profile=, --include-targets)
hackly:cleanup-outputs Delete old raw scanner outputs
hackly:dispatch-due Re-dispatch leftover pending tasks
queue:work Process scan jobs
schedule:work Hourly cleanup of old outputs (or cron schedule:run)

Configuration

Primary config: config/hackly.php — override via .env.

.env
QUEUE_CONNECTION=database
CACHE_STORE=database

# Safety
HACKLY_ALLOWLIST_ONLY=false
HACKLY_ALLOWLIST=example.com,203.0.113.10
HACKLY_ALLOW_PRIVATE_TARGETS=true

# Soft rate limits
HACKLY_PER_TARGET_PER_MINUTE=2
HACKLY_GLOBAL_CONCURRENT=5
HACKLY_JITTER_SECONDS=5
HACKLY_TASK_SPACING_SECONDS=10
HACKLY_DEEP_COOLDOWN_HOURS=24
HACKLY_QUIET_HOURS_ENABLED=false

# Job timeout must exceed longest scanner (ZAP ~900s)
HACKLY_JOB_TIMEOUT=960
DB_QUEUE_RETRY_AFTER=1020

# Target binary paths
HACKLY_NMAP=nmap
HACKLY_NUCLEI=nuclei
# macOS: HACKLY_ZAP=/Applications/ZAP.app/Contents/Java/zap.sh
HACKLY_ZAP=zap.sh

# GitHub repository scanning
HACKLY_GIT=git
HACKLY_COMPOSER=composer
HACKLY_SEMGREP=semgrep
HACKLY_TRIVY=trivy
HACKLY_GITLEAKS=gitleaks
HACKLY_CHECKOV=checkov
# HACKLY_SEMGREP_CONFIG=p/php
# HACKLY_OSV_ENABLED=true
# HACKLY_REPO_HIDE_UNREACHABLE=false
# HACKLY_REPO_DROP_NOISE=false

Security model

  • Target scans require ownership verification (DNS TXT for domains)
  • Repository scans require a GitHub token with read access to that repo
  • Linking Targets ↔ Repositories is optional; scans remain independently startable
  • Optional allowlist and private-IP blocking for Targets
  • Soft rate limits, jitter, task spacing, and quiet hours
  • Deep target profile has a cooldown between runs
  • GitHub PATs are stored encrypted at rest (APP_KEY) via the GitHub tokens UI
  • Repo workspace clones are removed after finalize when HACKLY_REPO_CLEANUP=true (default)
  • Admin accounts support TOTP and email multi-factor authentication
Hackly is an orchestration layer — it does not replace responsible disclosure policies or scoped pentest agreements. PHP reachability / noise reduction is heuristic (strong signal for Laravel apps), not a full interprocedural guarantee.

Production tips

  • Set HACKLY_ALLOW_PRIVATE_TARGETS=false
  • Prefer HACKLY_ALLOWLIST_ONLY=true with an explicit allowlist
  • Configure real mail for email 2FA (MAIL_MAILER=…)
  • Change the seeded admin password immediately
  • Store GitHub PATs only via the GitHub tokens UI
  • Run both install scripts on the scan worker host, then hackly:check-binaries as the queue user
  • Run a persistent queue:work; optionally schedule:work (or cron) for output cleanup

Source and issues: github.com/andreapollastri/hackly