Commit Graph

47 Commits

Author SHA1 Message Date
Tigah fcccff5532 feat(modules): detect exposed ml experiment trackers (#243)
add recon modules for self-hosted training and experiment-tracking
platforms reachable without auth: mlflow, tensorboard, aim, and
determined disclose experiments, the artifact store, training run paths,
and cluster topology over unauthenticated apis.
2026-07-02 12:55:47 -07:00
Tigah a549102bb0 feat(modules): detect exposed ai image generation servers (#241)
add recon modules for self-hosted image generation servers reachable
without auth: comfyui, automatic1111, fooocus-api, and iopaint each
expose unauthenticated generation or editing and disclose the installed
models.
2026-07-02 12:55:44 -07:00
Tigah 7e3648e06d feat(modules): detect exposed data labeling tools (#239)
add recon modules for unauthenticated annotation servers that leak projects or config without a key: cvat and label studio.
2026-07-02 12:55:41 -07:00
Tigah 9e2965b777 feat(modules): detect exposed llm chat frontends (#237)
add recon modules for unauthenticated chat uis that leak config or allow open signup without a key: open webui, librechat, anythingllm, and nextchat.
2026-07-02 12:55:39 -07:00
Tigah 37a1a9e0ec feat(modules): detect exposed huggingface inference servers (#234)
add recon modules for unauthenticated text-generation-inference (tgi) and text-embeddings-inference (tei) servers that leak model info without a key.
2026-07-02 12:55:36 -07:00
Tigah 0c6a8db5a7 feat(modules): add favicon fingerprint demo module (#184)
a favicon-gitlab info module showing the favicon hash matcher in use,
with a sync test pinning the module's hash to the shared fingerprint pkg.
2026-06-22 21:42:43 -07:00
Tigah b31234c1bc feat(modules): add netdata and cadvisor exposure modules (#217)
modules/recon/netdata-api-exposure.yaml flags an exposed Netdata agent through its
unauthenticated /api/v1/info endpoint, keyed on the mirrored_hosts and cores_total
fields a generic info response does not carry, then extracts the agent version.

modules/recon/cadvisor-api-exposure.yaml flags an exposed cAdvisor container monitor
through its /api/v1.3/machine endpoint, keyed on the machine_id and cpu_frequency_khz
fields, then extracts the machine id.

internal/modules/metrics_exposure_test.go drives both modules through
ExecuteHTTPModule and asserts the leak alongside the near misses a strict review
wants pinned: each service with one keying field missing, a generic json, a plain 200
and a 404.

verify: go test ./internal/modules, each matcher and extractor proven to bite
(break -> red, restore -> green).
2026-06-22 19:52:30 -07:00
Tigah caeff3944d feat(modules): add docker, kubernetes and kubelet api exposure modules (#212)
modules/recon/docker-api-exposure.yaml flags an unauthenticated Docker Engine
api, keyed on the api version paired with the minimum api version that a generic
version endpoint does not carry, then extracts the engine version.

modules/recon/kubernetes-api-exposure.yaml flags an internet reachable Kubernetes
api server through its anonymous version endpoint, keyed on the git version
paired with a build field, then extracts the version.

modules/recon/kubelet-api-exposure.yaml flags an exposed kubelet whose pod list
leaks the cluster workload, keyed on the PodList kind paired with an api version,
then extracts a pod namespace.

internal/modules/runtime_api_exposure_test.go drives the three modules end to end
through ExecuteHTTPModule and asserts the leak alongside the near misses a strict
review wants pinned: a generic version response, each service with one keying
field missing, a service list that is not a pod list, a plain 200 and a 404.

verify: go test ./internal/modules, each matcher and extractor proven to bite
(break -> red, restore -> green).
2026-06-22 19:52:25 -07:00
Tigah 8c8f8afba3 feat(modules): add maven, gradle and nuget credential exposure modules (#209)
modules/recon/maven-settings-exposure.yaml flags an exposed settings.xml through
the settings or servers structure paired with a password element, so a mirror
only config is not reported, then extracts the server username.

modules/recon/gradle-properties-exposure.yaml flags an exposed gradle.properties
through a password, secret or token property with a value on the same line,
skipping comments and empty assignments, then extracts the property name.

modules/recon/nuget-config-exposure.yaml flags an exposed nuget.config through a
packageSourceCredentials section paired with a cleartext password key, so a
plain package source list or an appsettings password is not reported, then
extracts the feed username.

internal/modules/buildtool_credential_exposure_test.go drives the three modules
end to end through ExecuteHTTPModule and asserts the leak alongside the near
misses a strict review wants pinned: a mirror only settings, a non credential
properties file, a commented password, an empty value, a plain source list, an
appsettings password, an html tutorial for each file, a plain 200 and a 404.

verify: go test ./internal/modules, each matcher and extractor proven to bite
(break -> red, restore -> green).
2026-06-22 19:52:21 -07:00
Tigah 1e47b6547e feat(modules): add terraform, kubeconfig and compose exposure modules (#201)
modules/recon/terraform-state-exposure.yaml flags an exposed terraform state
file on the terraform_version key paired with a state structure key, then
extracts the version. the structure key keeps a document that merely mentions
terraform_version from matching.

modules/recon/kubeconfig-exposure.yaml flags an exposed kubeconfig on the
kind: Config marker paired with a cluster or credential key, then extracts the
cluster api endpoint. it catches an exec auth kubeconfig with no embedded key
since the cluster block alone is a leak.

modules/recon/docker-compose-exposure.yaml flags an exposed compose file on the
services key paired with a service definition key, then extracts the first
image reference to surface the stack and its versions.

each module pairs a unique marker with a structure key and rejects an html
body, so a page that only names the marker is not a leak.

internal/modules/infra_config_exposure_test.go drives the three modules end to
end through ExecuteHTTPModule and asserts the leak alongside the near misses a
strict review wants pinned: a bare terraform_version mention, a bare
kind: Config mention, a bare services key, an html page carrying the markers, a
plain 200 body and a 404, none of which may match.

verify: go test ./internal/modules, each marker, structure gate, guard and
extractor proven to bite (break -> red, restore -> green).
2026-06-22 19:52:16 -07:00
Tigah 368d658882 feat(modules): add grafana, kibana and jenkins login panel modules (#187)
* feat(modules): add grafana, kibana and jenkins login panel modules

* test(modules): cover the login panel modules
2026-06-22 19:52:12 -07:00
Tigah c6cedf3f55 feat(modules): add env file exposure module (#185)
* feat(modules): add env file exposure module

* test(modules): cover the env file exposure module
2026-06-22 19:52:07 -07:00
Tigah 1b41b5ed65 feat(modules): add ignition, profiler and heapdump exposure modules (#196)
modules/recon/laravel-ignition-exposure.yaml probes the live
/_ignition/health-check endpoint and extracts can_execute_commands, the flag
that marks the CVE-2021-3129 remote code execution surface. this is an active
probe, complementary to the version based ignition entry in the framework cve
map.

modules/recon/symfony-profiler-exposure.yaml flags an exposed web profiler on
its structural markers and extracts a request token to pivot to a captured
request.

modules/recon/spring-heapdump-exposure.yaml flags an exposed actuator heap
dump on the hprof magic anchored at the start of the body, which a json marker
module cannot see because the dump is binary, and extracts the hprof version.
the anchor keeps a page that merely quotes the magic from matching.

internal/modules/debug_exposure_test.go drives the three modules end to end
through ExecuteHTTPModule and asserts the leak alongside the near misses a
strict review wants pinned: a prose mention of ignition, the hprof magic away
from the start, a plain 200 body and a 404, none of which may match, plus an
exposed ignition with command execution disabled that still flags and reports
the false flag.

verify: go test ./internal/modules, each matcher, anchor and extractor proven
to bite (break -> red, restore -> green).
2026-06-22 18:29:10 -07:00
Tigah 301f758053 feat(modules): add server status page exposure module (#150)
apache mod_status and nginx stub_status pages expose worker state,
client addresses and request urls. match the three real shapes (the
apache html "Apache Server Status for" page, the apache auto Scoreboard
line, and the nginx "Active connections" plus "server accepts handled
requests" block) and extract the apache version when present.
2026-06-22 18:26:19 -07:00
Tigah d7d669e300 feat(modules): add spring boot actuator exposure module (#144)
probe /actuator and the env, health and metrics endpoints for an
exposed actuator, which leaks environment variables, config and
runtime internals. sif already fingerprints spring boot as a framework
but never checks whether its actuator endpoints are left open.

the matchers key on structural shapes rather than bare tokens: the env
propertySources array, a hal index whose links resolve under /actuator,
detailed health components, and jvm metric names. a bare {"status":"UP"}
health check, a generic hateoas api and prose mentions do not match.

a custom management base-path (actuator moved off /actuator) and spring
boot 1.x root endpoints are not covered.
2026-06-22 18:23:48 -07:00
Tigah db862992b5 feat(modules): add joomla, drupal and magento config exposure modules (#211)
modules/recon/joomla-config-exposure.yaml flags an exposed configuration.php
backup through the JConfig class paired with the password property, so a generic
php class is not reported, then extracts the database password.

modules/recon/drupal-config-exposure.yaml flags an exposed settings.php backup
through the databases array paired with a literal password value, so an array
that lacks the marker or resolves the password from the environment is not
reported, then extracts the password.

modules/recon/magento-config-exposure.yaml flags an exposed app/etc/env.php
backup through the crypt or mode marker paired with a literal key or password
value, so a generic return array or a cloud placeholder is not reported, then
extracts the crypt key.

internal/modules/cms_config_exposure_test.go drives the three modules end to end
through ExecuteHTTPModule and asserts the leak alongside the near misses a strict
review wants pinned: a config missing its password, a generic php class, an array
without the databases marker, a databases array with no password, an env
indirection password, a return array without a magento marker, a magento config
with no credential, a cloud placeholder key, an html tutorial for each file, a
plain 200 and a 404.

verify: go test ./internal/modules, each matcher and extractor proven to bite
(break -> red, restore -> green).
2026-06-22 18:21:32 -07:00
Tigah 273dcdc30d feat(modules): add adminer and phpmyadmin database panel modules (#186)
* feat(modules): add adminer and phpmyadmin database panel modules

* test(modules): cover the database panel modules
2026-06-22 18:18:37 -07:00
Tigah cf159ad4a9 feat(modules): add svn, mercurial and bazaar exposure modules (#210)
modules/recon/svn-exposure.yaml flags an exposed .svn working copy through the
wc.db sqlite header anchored at the first byte paired with a working copy table
name, so a generic sqlite database is not reported, then extracts the
repository url.

modules/recon/mercurial-exposure.yaml flags an exposed .hg repository through
the revlog format requirements that the requires file lists, so prose that
names mercurial is not reported, then extracts the requirement.

modules/recon/bazaar-exposure.yaml flags an exposed .bzr repository through the
Bazaar meta directory signature, so a page that names a bazaar is not reported,
then extracts the format.

internal/modules/vcs_metadata_exposure_test.go drives the three modules end to
end through ExecuteHTTPModule and asserts the leak alongside the near misses a
strict review wants pinned: a generic sqlite database, an unanchored magic,
prose naming mercurial, a marketplace page, an html tutorial for the text
formats, a plain 200 and a 404.

verify: go test ./internal/modules, each matcher and extractor proven to bite
(break -> red, restore -> green).
2026-06-22 18:18:16 -07:00
Tigah 4a84790f02 feat(modules): add netrc, pgpass and my.cnf exposure modules (#208)
modules/recon/netrc-exposure.yaml flags an exposed .netrc through the machine
login password grammar, requiring the keywords in order so prose that names
them out of order does not match, then extracts the machine host.

modules/recon/pgpass-exposure.yaml flags an exposed .pgpass through a single
line host:port:database:user:password record with a numeric or wildcard port,
which a yaml config or a multi line body does not satisfy, then extracts the
host.

modules/recon/mysql-client-config-exposure.yaml flags an exposed .my.cnf
through a client section paired with a cleartext password key, so a section
without a credential is not reported, then extracts the client user.

internal/modules/dotfile_credential_exposure_test.go drives the three modules
end to end through ExecuteHTTPModule and asserts the leak alongside the near
misses a strict review wants pinned: out of order prose, a yaml db config, a
non numeric port, a multi line body, a section without a password, a password
without a section, an html tutorial for each file, a plain 200 and a 404.

verify: go test ./internal/modules, each matcher and extractor proven to bite
(break -> red, restore -> green).
2026-06-22 18:15:51 -07:00
Tigah e2f59637ec feat(modules): add docker registry and harbor exposure modules (#218)
modules/recon/docker-registry-api-exposure.yaml flags a Docker registry reachable
anonymously through its /v2/ base, keyed on a 200 paired with the
Docker-Distribution-Api-Version: registry/2.0 response header (the header rides on a
401 too, so the 200 gate is what proves anonymous reach), then extracts the api
version.

modules/recon/harbor-api-exposure.yaml flags an exposed Harbor registry through its
unauthenticated /api/v2.0/systeminfo endpoint, keyed on the harbor_version and
auth_mode fields, then extracts the harbor version.

internal/modules/registry_exposure_test.go drives both modules through
ExecuteHTTPModule and asserts the leak alongside the near misses: docker registry on
a header-less 200 and on a 401 that still carries the header, harbor with one keying
field missing, a plain 200 and a 404.

verify: go test ./internal/modules, each matcher and extractor proven to bite
(break -> red, restore -> green).
2026-06-22 18:13:20 -07:00
Tigah c68b077a22 feat(modules): add phpinfo exposure module (#145)
probe phpinfo.php, info.php, php_info.php, test.php and i.php for an
exposed phpinfo() page, which leaks the full php config, environment,
loaded extensions and $_SERVER (often credentials).

a finding requires both a phpinfo header (the version-stamped title or
the zend engine credit) and a config table row (the PHP Version or
System cell), so a page that only quotes one of those in prose does not
match. the php version is read from the config table.
2026-06-22 18:08:12 -07:00
Tigah 8c732f9955 feat(modules): add prometheus metrics exposure module (#147)
an exposed /metrics endpoint leaks process, runtime and request
internals that aid recon. match the prometheus text exposition format
structurally (a # HELP line plus a # TYPE line ending in one of the
known metric types) so a json /metrics or prose that mentions the
format does not trip it. extract the go runtime version from go_info
when it is present.
2026-06-22 18:01:02 -07:00
Tigah 27a8a27880 feat(modules): add werkzeug debugger exposure module (#149)
a flask app left on debug=True wraps the wsgi app in werkzeug's
DebuggedApplication, which serves its debugger assets unauthenticated:
GET /?__debugger__=yes&cmd=resource&f=debugger.js returns the debugger
javascript with no pin and no live exception required. that exposes the
interactive console (an rce vector) and tracebacks that leak source and
config.

probe that asset path and match two javascript anchors stable across
werkzeug 0.14 through 3.0 so a page that only references the debugger
does not match, then read the werkzeug version from the server header.
2026-06-22 17:58:22 -07:00
Tigah 9340a8be0e feat(modules): add graphql introspection detection module (#139)
add a yaml module that posts a minimal introspection query to common
graphql paths and flags endpoints whose schema is exposed. the matcher
keys on the json result shape ("__schema":{ and "queryType":{) instead of
the bare __schema/queryType substrings, so a disabled endpoint that echoes
the query in its error does not false-positive. scoped to post+json
requests; get-only and persisted-query endpoints are out of scope.
2026-06-22 17:53:28 -07:00
Tigah 733578e6ec feat(modules): add django debug page exposure module (#148)
a django app left on DEBUG=True renders a technical 404 or 500 page
that leaks settings, the url config, the traceback and request details.
a non-existent path triggers the 404 page on such apps; match the
"seeing this error because you have DEBUG = True" footer together with
the page chrome so a normal 404 does not match, then extract the django
version.
2026-06-22 17:48:36 -07:00
Tigah 1bbc564170 feat(modules): add elasticsearch exposure module (#151)
an elasticsearch node left without authentication answers its root
banner to any client, and versions before 8.0 ship with no auth by
default, so a 200 at / means every index is readable without
credentials. match the "You Know, for Search" tagline together with
the lucene_version field so a page that only quotes the tagline in
prose does not match, then read the cluster version from the
version.number field.
2026-06-22 17:45:49 -07:00
Tigah 12b56661ac feat(modules): add couchdb exposure module (#152)
probe /_all_dbs instead of the / welcome banner: couchdb serves the
banner publicly even on a secured 3.x, so a 200 there only proves an
instance is reachable. /_all_dbs is admin-gated by default since 3.0
(admin_only_all_dbs), so a 200 listing means the database names are
readable without auth on every version, while a secured server returns
401. the match requires a json array carrying a system database
(_users, _replicator or _global_changes), which keeps non-couchdb
arrays and prose clean.

no version is extracted: the /_all_dbs array carries no version string.
instances with renamed or deleted system databases are not matched.
2026-06-22 17:41:17 -07:00
Tigah c03fa7d336 feat(modules): add portainer, traefik, keycloak and rabbitmq panel modules (#190) 2026-06-22 17:26:16 -07:00
Tigah 45f5302e1f feat(modules): add aws, npmrc and docker credential file exposure modules (#195)
modules/recon/aws-credentials-exposure.yaml flags exposed .aws/credentials,
.s3cfg and .boto files on the access and secret key markers, and extracts
the AKIA/ASIA access key id.

modules/recon/npmrc-exposure.yaml flags a .npmrc only when it carries an
auth token or password, not a bare registry config, and extracts the
registry the token belongs to.

modules/recon/docker-config-exposure.yaml flags .docker/config.json and the
legacy .dockercfg on the base64 auth field, and extracts the registry host.

each module ands a negative matcher on the usual html markers so a 200 page
that merely names a key is not a hit, the same guard the env exposure module
uses.

internal/modules/credential_exposure_test.go drives the three modules end to
end through ExecuteHTTPModule and asserts the leak alongside the near misses
a strict review wants pinned: an html doc that only names a key, a plain 200
body, a 404, and a jwt shaped docker auth value, none of which may match.

verify: go test ./internal/modules, each matcher, guard and extractor proven
to bite (break -> red, restore -> green).
2026-06-22 17:24:06 -07:00
Tigah f6f9a2bbf7 feat(modules): add spring, appsettings and wp-config exposure modules (#206)
modules/recon/spring-application-config-exposure.yaml flags an exposed Spring
application config, in either properties or yaml form, on a datasource marker
paired with a credential field, then extracts the jdbc url. requiring the
credential keeps a config that holds no secret from being reported.

modules/recon/appsettings-exposure.yaml flags an exposed ASP.NET Core
appsettings.json, the .NET Core counterpart to web.config, on a
ConnectionStrings section paired with an inline password, then extracts the
connection string.

modules/recon/wp-config-backup-exposure.yaml flags an exposed wp-config backup,
the leftover .bak or swap copy that serves raw php, on the DB_PASSWORD constant
paired with another db define, then extracts the database password.

internal/modules/app_config_exposure_test.go drives the three modules end to
end through ExecuteHTTPModule and asserts the leak alongside the near misses a
strict review wants pinned: a config with no credential, a password outside a
connection strings section, a passwordless connection string, prose that names
DB_PASSWORD, a config shown in an html page, a plain 200 body and a 404, none
of which may match.

verify: go test ./internal/modules, each matcher, marker, guard and extractor
proven to bite (break -> red, restore -> green).
2026-06-22 17:19:56 -07:00
Tigah a9fde8c695 feat(modules): add rails config secret exposure modules (#199)
modules/recon/rails-database-yml-exposure.yaml flags an exposed
config/database.yml on the adapter key paired with a credential key, then
extracts the database name. requiring a credential key keeps a credential free
sqlite config from being reported as a high severity leak.

modules/recon/rails-secrets-yml-exposure.yaml flags an exposed
config/secrets.yml on the secret_key_base key and extracts the secret, the
value an attacker needs to forge rails sessions.

modules/recon/rails-master-key-exposure.yaml flags an exposed master key, the
32 hex value that decrypts the encrypted credentials store. the matcher anchors
the hex to the whole body so a longer digest such as a sha256 served at the
same path does not match, and the same probe covers config/credentials.

internal/modules/rails_secret_exposure_test.go drives the three modules end to
end through ExecuteHTTPModule and asserts the leak alongside the near misses a
strict review wants pinned: a credential free sqlite config, a longer hex
digest, a hex value away from the body start, an html page naming the markers,
a config without the markers and a 404, none of which may match.

verify: go test ./internal/modules, each matcher, guard, anchor and extractor
proven to bite (break -> red, restore -> green).
2026-06-22 17:19:50 -07:00
Tigah 94d375fc3b feat(modules): add editor sftp deploy config exposure modules (#198)
modules/recon/vscode-sftp-exposure.yaml flags an exposed vscode-sftp config on
its tool keys, remotePath and uploadOnSave, then extracts the deploy host. the
tool keys keep an unrelated json config that merely carries host and credential
fields from matching.

modules/recon/sublime-sftp-exposure.yaml flags an exposed Sublime SFTP config
on its snake case keys, upload_on_save and sync_down_on_open, and extracts the
deploy host.

modules/recon/ftpconfig-exposure.yaml flags an exposed remote-ftp config on its
connection timeout keys, connTimeout and pasvTimeout, and extracts the deploy
host.

each module requires a credential field alongside the tool key and rejects an
html body, so a login page served on the same path is not a leak and an
unrelated json config is not a high severity credential finding.

internal/modules/deploy_config_exposure_test.go drives the three modules end to
end through ExecuteHTTPModule and asserts the leak alongside the near misses a
strict review wants pinned: an html login page carrying the same keys, a plain
json config without the tool keys, a tool config with a host but no credential
field and a 404, none of which may match. it also pins a key auth config with
no password as a leak the credential matcher must still catch.

verify: go test ./internal/modules, each matcher, guard and extractor proven to
bite (break -> red, restore -> green).
2026-06-22 17:19:43 -07:00
Tigah c6741e0f16 feat(modules): add htpasswd, web.config and htaccess exposure modules (#202)
modules/recon/htpasswd-exposure.yaml flags an exposed htpasswd file on a line
that holds a recognised password hash, an apache md5, a bcrypt, a sha crypt or
a {SHA} digest, then extracts the user. matching the hash format keeps a line
that holds a plaintext value from being reported.

modules/recon/webconfig-exposure.yaml flags an exposed asp.net web.config on the
configuration root paired with a dotnet section, then extracts a connection
string, the value that carries the database server and password.

modules/recon/htaccess-exposure.yaml flags an exposed htaccess file on its
apache directives and extracts the AuthUserFile path, which points at the
password file to fetch next.

internal/modules/webserver_config_exposure_test.go drives the three modules end
to end through ExecuteHTTPModule and asserts the leak alongside the near misses
a strict review wants pinned: a plaintext htpasswd line, a configuration without
a dotnet section, an html page, a plain 200 body and a 404, none of which may
match.

verify: go test ./internal/modules, each matcher, hash format, section gate,
guard and extractor proven to bite (break -> red, restore -> green).
2026-06-22 17:15:01 -07:00
Tigah 6a8ce9c07b feat(modules): add vault, consul and etcd api exposure modules (#207)
modules/recon/vault-api-exposure.yaml flags an internet reachable HashiCorp
Vault through its unauthenticated seal-status, keyed on the sealed flag paired
with a vault-only status field, then extracts the version for cve matching.

modules/recon/consul-api-exposure.yaml flags a Consul http api that answers
without an acl token, keyed on the Datacenter field paired with an agent or
node marker, then extracts the datacenter.

modules/recon/etcd-api-exposure.yaml flags an exposed etcd through its version
endpoint, keyed on the etcdserver and etcdcluster fields that a generic version
response does not carry, then extracts the server version.

internal/modules/orchestration_api_exposure_test.go drives the three modules
end to end through ExecuteHTTPModule and asserts the leak alongside the near
misses a strict review wants pinned: a sealed flag with no vault field, a
datacenter field alone, a version response from another service, a partial etcd
reply, a plain 200 body and a 404, none of which may match.

verify: go test ./internal/modules, each matcher and extractor proven to bite
(break -> red, restore -> green).
2026-06-22 17:13:07 -07:00
Tigah 355df83b59 feat(modules): add private key, git and pypi secret exposure modules (#205)
modules/recon/private-key-exposure.yaml flags an exposed PEM private key on
the BEGIN PRIVATE KEY marker, so a public key or prose that merely names a key
is left alone, then extracts the key type.

modules/recon/git-credentials-exposure.yaml flags an exposed git credential
store on a remote url that carries an inline password, paired with a guard
that drops a url shown inside an html page, then extracts the host the
credential reaches.

modules/recon/pypirc-exposure.yaml flags an exposed pypirc on an index section
paired with a credential field, then extracts the pypi upload token. requiring
the credential keeps a bare index listing from being reported.

internal/modules/secret_file_exposure_test.go drives the three modules end to
end through ExecuteHTTPModule and asserts the leak alongside the near misses a
strict review wants pinned: a public key, prose that names a key, a remote url
with no password, a pypi section with no credential, a credential shown in an
html page, a plain 200 body and a 404, none of which may match.

verify: go test ./internal/modules, each matcher, marker, guard and extractor
proven to bite (break -> red, restore -> green).
2026-06-22 17:10:45 -07:00
Tigah 570592c317 feat(modules): add airflow, flink and kafka connect exposure modules (#214)
modules/recon/airflow-api-exposure.yaml flags an exposed Apache Airflow webserver
through its unauthenticated health endpoint, keyed on the metadatabase and
scheduler health blocks, then extracts the scheduler heartbeat.

modules/recon/flink-api-exposure.yaml flags an exposed Apache Flink dashboard,
keyed on the flink version paired with the slot total that a generic overview does
not carry, then extracts the flink version.

modules/recon/kafka-connect-api-exposure.yaml flags an exposed Kafka Connect rest
api, keyed on the kafka cluster id paired with the version, then extracts the
version.

internal/modules/data_pipeline_api_exposure_test.go drives the three modules end to
end through ExecuteHTTPModule and asserts the leak alongside the near misses a
strict review wants pinned: each service with one keying field missing, a generic
health response, a plain 200 and a 404.

verify: go test ./internal/modules, each matcher and extractor proven to bite
(break -> red, restore -> green).
2026-06-22 17:07:25 -07:00
Tigah 761e570d59 feat(modules): add sql dump, sqlite and redis rdb exposure modules (#204)
modules/recon/sql-dump-exposure.yaml flags an exposed SQL dump on its
mysqldump and pg_dump idioms paired against a guard that drops SQL shown
inside an html page, then extracts the dumped table name.

modules/recon/sqlite-database-exposure.yaml flags an exposed SQLite file on
the 16 byte format magic anchored to the start of the body, then extracts a
schema table name. anchoring the magic keeps a page that merely embeds the
header from being reported.

modules/recon/redis-dump-exposure.yaml flags an exposed Redis RDB snapshot on
the RDB magic anchored to the start of the body, then extracts the format
version.

internal/modules/database_file_exposure_test.go drives the three modules end
to end through ExecuteHTTPModule and asserts the leak alongside the near
misses a strict review wants pinned: a SQL tutorial page, a bare select, prose
that names the sqlite or redis format, a header embedded mid body, a plain 200
body and a 404, none of which may match.

verify: go test ./internal/modules, each matcher, magic anchor, guard and
extractor proven to bite (break -> red, restore -> green).
2026-06-22 17:07:15 -07:00
Tigah 28a01f0f83 feat(modules): add riak, couchbase and druid api exposure modules (#216)
modules/recon/riak-api-exposure.yaml flags an exposed Riak http api reachable
without authentication, keyed on the riak kv version paired with the core version,
then extracts the kv version.

modules/recon/couchbase-api-exposure.yaml flags an exposed Couchbase cluster
management api, keyed on the implementation version paired with the components
version that the bootstrap pool reports, then extracts the implementation version.

modules/recon/druid-api-exposure.yaml flags an exposed Apache Druid process that
runs without authentication, keyed on the druid package namespace paired with the
process memory block, then extracts the druid version.

internal/modules/distributed_db_exposure_test.go drives the three modules end to
end through ExecuteHTTPModule and asserts the leak alongside the near misses a
strict review wants pinned: each service with one keying field missing, a generic
version response, a plain 200 and a 404.

verify: go test ./internal/modules, each matcher and extractor proven to bite
(break -> red, restore -> green).
2026-06-22 17:06:51 -07:00
Tigah 7788550722 feat(modules): add qdrant, weaviate and chroma exposure modules (#222)
modules/recon/qdrant-api-exposure.yaml flags a Qdrant vector database that
serves its collections without an api key, keyed on the result envelope wrapping
a collections array paired with the ok status, then extracts the first
collection name. Qdrant gates /collections behind the api key, so an answer here
means the catalog is readable.

modules/recon/weaviate-api-exposure.yaml flags a Weaviate vector database that
leaks its host address and version over the meta api, keyed on the url-valued
hostname paired with the version field, then extracts the hostname. Weaviate
drops the modules field when none are enabled, so the match leans on the
hostname, which it always renders as a scheme and host.

modules/recon/chroma-api-exposure.yaml flags a reachable Chroma vector database
by its heartbeat api on both the v1 and v2 paths, keyed on the nanosecond
heartbeat field. The heartbeat stays anonymous by design, so this is rated as a
reachability signal rather than an auth bypass.

internal/modules/vector_db_exposure_test.go drives the three modules end to end
through ExecuteHTTPModule and asserts the leak alongside the near misses a strict
review wants pinned: each service with one keying field missing, a bare hostname,
a generic version response, a plain 200 and a 404.

verify: go test ./internal/modules, each matcher and extractor proven to bite
(break -> red, restore -> green).
2026-06-22 16:54:03 -07:00
Tigah 40482a8409 feat(modules): add argo cd exposure module (#219)
modules/recon/argocd-api-exposure.yaml flags an exposed Argo CD api server through
its unauthenticated /api/version endpoint, keyed on the KustomizeVersion and
HelmVersion fields a generic version response does not carry, then extracts the
server version.

internal/modules/argocd_exposure_test.go drives the module through ExecuteHTTPModule
and asserts the leak alongside the near misses: each keying field missing on its own,
a generic version json, a plain 200 and a 404.

verify: go test ./internal/modules, each matcher and extractor proven to bite
(break -> red, restore -> green).
2026-06-22 16:49:52 -07:00
Tigah 3ed9ea4b6f feat(modules): add kong, jolokia and nats api exposure modules (#215)
modules/recon/kong-api-exposure.yaml flags an exposed Kong admin api that grants
full control of the gateway, keyed on the available plugins map paired with the
admin listen address that the node reports, then extracts the kong version.

modules/recon/jolokia-api-exposure.yaml flags an exposed Jolokia agent that
bridges http to jmx, keyed on the agent and protocol fields of its version
response, then extracts the agent version.

modules/recon/nats-api-exposure.yaml flags an exposed NATS monitoring endpoint
that leaks the server topology, keyed on the server id paired with the max
payload, then extracts the server version.

internal/modules/management_api_exposure_test.go drives the three modules end to
end through ExecuteHTTPModule and asserts the leak alongside the near misses a
strict review wants pinned: each service with one keying field missing, a generic
version response, a plain 200 and a 404.

verify: go test ./internal/modules, each matcher and extractor proven to bite
(break -> red, restore -> green).
2026-06-22 16:49:45 -07:00
Tigah 612bb61d00 feat(modules): add solr, spark and hadoop yarn api exposure modules (#213)
modules/recon/solr-api-exposure.yaml flags an exposed Apache Solr admin api,
keyed on the solr spec version paired with the solr home that a generic json
endpoint does not carry, then extracts the solr version.

modules/recon/spark-api-exposure.yaml flags an exposed Apache Spark master whose
cluster state is reachable without authentication, keyed on a spark:// master url
paired with the alive worker count, then extracts the master url.

modules/recon/hadoop-yarn-api-exposure.yaml flags an exposed Hadoop YARN resource
manager, keyed on the cluster info wrapper paired with the resource manager
version, then extracts the hadoop version.

internal/modules/bigdata_api_exposure_test.go drives the three modules end to end
through ExecuteHTTPModule and asserts the leak alongside the near misses a strict
review wants pinned: each service with one keying field missing, a non spark url
behind the worker count, a generic json endpoint, a plain 200 and a 404.

verify: go test ./internal/modules, each matcher and extractor proven to bite
(break -> red, restore -> green).
2026-06-22 16:49:38 -07:00
Tigah d0e986736d feat(modules): add influxdb, arangodb and neo4j exposure modules (#221)
modules/recon/influxdb-api-exposure.yaml flags an exposed InfluxDB instance through
its unauthenticated /health endpoint, keyed on the influxdb name paired with the
ready-for-queries health message, then extracts the version.

modules/recon/arangodb-api-exposure.yaml flags an ArangoDB instance reachable
anonymously through its /_api/version endpoint, keyed on the arango server name
paired with the version field, then extracts the version. the 200 gate is what
proves anonymous reach: an auth-enabled instance answers with a 401.

modules/recon/neo4j-api-exposure.yaml flags an exposed Neo4j instance through its
unauthenticated root discovery endpoint, keyed on the neo4j version paired with the
neo4j edition, then extracts the version.

internal/modules/http_database_exposure_test.go drives the three modules through
ExecuteHTTPModule and asserts the leak alongside the near misses a strict review
wants pinned: each service with one keying field missing, a non-arango response, an
arango that requires auth, a generic health json, a plain 200 and a 404.

verify: go test ./internal/modules, each matcher and extractor proven to bite
(break -> red, restore -> green).
2026-06-22 16:48:41 -07:00
Tigah 72f59532cf feat(modules): add metabase, zeppelin and jupyter exposure modules (#220)
modules/recon/metabase-api-exposure.yaml flags a Metabase instance that exposes
a live setup token without authentication, keyed on a non-null uuid token paired
with the anonymous tracking setting, then extracts the version tag. A live token
is the pre-auth chain behind CVE-2023-38646; a patched instance reports it as
null and is left alone.

modules/recon/zeppelin-api-exposure.yaml flags an Apache Zeppelin server that
discloses its version and build commit over the anonymous version api, keyed on
the version banner paired with the git commit id, then extracts the version. The
endpoint stays anonymous even on a shiro-secured instance, so this is rated as a
version leak rather than an auth bypass.

modules/recon/jupyter-api-exposure.yaml flags a Jupyter server whose status api
answers without a token, keyed on the activity, connections and kernels fields
it reports, then extracts the running kernel count.

internal/modules/analytics_ui_exposure_test.go drives the three modules end to
end through ExecuteHTTPModule and asserts the leak alongside the near misses a
strict review wants pinned: each service with one keying field missing, a
patched metabase that nulls its token, a generic version response, a plain 200
and a 404.

verify: go test ./internal/modules, each matcher and extractor proven to bite
(break -> red, restore -> green).
2026-06-22 16:48:34 -07:00
Tigah 68075b6901 feat(modules): add ghost, magento and typo3 detection modules (#138)
cover three platforms the built-in cms scanner misses (it only handles
wordpress, drupal and joomla). markers are structural: generator meta,
framework-specific js init and asset paths, not bare brand strings, so a
page that merely mentions the cms does not match. ghost also extracts its
version from the generator meta.
2026-06-22 16:47:18 -07:00
Tigah 1bbcefa685 feat(modules): add joomla cms detection module (#136)
the yaml module set had wordpress and drupal but not joomla, while the legacy
internal/scan/cms.go detects all three. the new module fills that gap so
--all-modules and -mt cms cover joomla too.

matches the generator meta (version-independent, joomla 1.5 through 5) plus
structural markers /media/system/js/core.js, /media/jui/ and
joomla-script-options, on the root and /administrator/. verified against live
and archived joomla sites, with no false positives on pages that only mention
joomla. version comes from a versioned generator or a leaked
X-Content-Encoded-By header.

additive: cms.go is untouched, the -cms scan is unchanged. whether converted
scanners should also run in the default flow is the open question on #52.

refs #52
2026-06-22 16:47:11 -07:00
vmfunc a5ea29b88d feat: add built-in yaml modules for security scanning 2026-01-03 05:57:10 -08:00