io.github.dir-ai/voyager-browser
Voyager's web-page sense: safe read-only observation of one live URL (structure, security, a11y).
Open source Open in the app JSON README (API)
About
Voyager's web-page sense: safe read-only observation of one live URL (structure, security, a11y).
Details
- Kind
- MCP servers
- Topic
- No topic detected
- Publisher
- dir-ai
- Origin
- official
- Category
- ferramentas
- Transport
- local
- Version
- 0.7.0
- Last push
- 2026-07-20T20:36:49Z
- Repository state
- ativo
- Language
- TypeScript
- License
- MIT
- Added
- 2026-08-29 03:02:42
- Updated
- 2026-08-29 03:02:42
- Origin id
io.github.dir-ai/voyager-browser
README
# @dir-ai/voyager-browser
**Voyager's web-page sense.** A safe, **read-only** observation of one live URL:
its structure, forms, links, script origins, **security posture** (HTTPS / HSTS /
CSP / mixed-content / cookies) and **accessibility signals** (lang, image alt
coverage, heading order) — each with a *described, never applied* fix.
It parses **static HTML** — **no JavaScript execution, no headless browser** — so
it's honest about what it can and cannot see (it will not render a client-side
SPA's runtime state). Every piece of page text is returned **framed as
untrusted**. It is **SSRF-gated**: it refuses non-`http(s)` URLs and anything
resolving to private, loopback, or cloud-metadata addresses.
> One sense in the [Voyager family](#the-voyager-family). Read-only, like all the
> senses — it never submits a form, clicks, or mutates anything.
## Install
```bash
npm i -g @dir-ai/voyager-browser
```
## Use
```bash
voyager-browser observe https://example.com
voyager-browser observe https://example.com --json
```
```
https://example.com/
https://example.com — 200; 3 finding(s), worst: medium. 0 form(s), 1 link(s).
title: Example Domain
security: https · a11y lang:yes alt:n/a
med HTTPS without HSTS
↳ add Strict-Transport-Security: max-age=63072000; includeSubDomains
med no Content-Security-Policy
↳ add a Content-Security-Policy to constrain scripts/resources
low no X-Content-Type-Options: nosniff
↳ add X-Content-Type-Options: nosniff
```
## As an MCP server
One tool, `observe_page`.
```json
{ "command": "voyager-browser", "args": ["mcp"] }
```
## As a library
```ts
import { observe } from '@dir-ai/voyager-browser'
const brief = await observe('https://example.com')
console.log(brief.summary)
console.log(brief.security) // { https, hsts, csp, mixedContent, thirdPartyScripts, … }
console.log(brief.forms) // insecure / cross-origin / sensitive flags
console.log(brief.findings) // severity + described fix
```
## What it looks for
- **Security posture (quality, not just presence)** — plain HTTP; missing/**weak** HSTS; missing CSP or a CSP graded weak (`unsafe-inline`/`unsafe-eval`/wildcard/no `object-src`/no `base-uri`); missing clickjacking protection (X-Frame-Options / `frame-ancestors`); missing `nosniff`, Referrer-Policy, Permissions-Policy; version-leaking `Server`/`X-Powered-By`; mixed content on an HTTPS page (origin-compared, not prefix); **per-cookie** Secure/HttpOnly; third-party scripts without **Subresource Integrity**.
- **Forms** — a form on HTTPS posting to plain HTTP (`critical`); a sensitive form (password/payment) posting cross-origin or over HTTP; a sensitive `POST` with no anti-CSRF token; sensitive data on `GET`.
- **Links** — external `target="_blank"` without `rel="noopener"` (reverse-tabnabbing).
- **Body-content leaks** — directory listings (Apache/nginx autoindex), language-specific **stack traces** (Python/Java/PHP/Node/Oracle/SQLSTATE/MySQL) and **verbose framework debug pages** (Werkzeug/Flask, Rails, Symfony/Whoops, ASP.NET YSOD) disclosed in the response body — each with the matched signature (framed).
- **Exposed JWTs** — JWT-shaped tokens found in the HTML, response headers, `Set-Cookie`, and same-origin bundles are **decoded** (header+payload, base64url, **no signature verification, no secret cracking**) and flagged for `alg:none` (`critical`), expired (`exp` in the past), or missing `exp`. Claim values are framed as untrusted.
- **Passive discovery of well-known sensitive paths** — bounded, same-origin, read-only `GET`s to a **short fixed list** (`/.git/config`, `/.env`, `/.svn/entries`, `/.DS_Store`, `/config.json`, `/wp-config.php~`, `/backup/`, `/uploads/`), flagging only a **confirmed body signature** — never a bare `200`. Pinned to the vetted IP; honours `--authorized`. Disable with `--no-discovery`.
- **Accessibility** — missing `<html lang>`, images without `alt`, skipped heading levels, unlabeled form fields.
- **Render honesty** — a `render: static | hybrid | client-heavy` field: if a page's content is JavaScript-rendered, the brief says so and marks itself PARTIAL rather than reporting a shell as clean.
- **Composition hints** — third-party script origins to vet with `@dir-ai/voyager` / `@dir-ai/voyager-net`.
## Safety
- **Read-only.** Fetches the page with a single GET; never submits, clicks, or mutates.
- **No code execution.** Static HTML parsing only — the page's JavaScript is never run.
- **SSRF-gated, with IP pinning.** Only `http(s)`; a single URL (no lists/credentials). The host is resolved, every address is classified canonically (IPv4-mapped IPv6, unspecified, CGNAT, NAT64, link-local, private, loopback, metadata all refused), and the connection is **pinned to the vetted IP** so DNS rebinding cannot swap in an internal address between the check and the fetch. **Every redirect hop is re-vetted and re-pinned.**
- **Untrusted by construction.** Every owner-controlled string that reaches the brief — title, headings, meta, links, form actions, field names — is injection-stripped and framed; the agent must treat it as data, not instructions.
- **Bounded.** One deadline covers headers **and** body; the body is byte-capped; a truncated read downgrades confidence and is never reported as "clean".
- **Honest limits.** It reads what the server sends. It does not see client-rendered state — and the `render` field says exactly how much it saw.
## Roadmap
- **v0.3** — same-origin JS-bundle static scan (exposed secrets/endpoints/source-maps), third-party/tracker/cookie inventory + tech fingerprinting, WCAG-mapped a11y depth, and a `CognitiveClaim` adapter so a page observation drops into a `@dir-ai/voyager-agent` mission (page → host → dependency chain).
- **v1.0** — an opt-in, consent-gated `--render` sandboxed headless pass (network-isolated, resource-capped) for true SPA/rendered-DOM coverage, always labeled as render-mode output; a stable finding-`kind` taxonomy and a full posture score.
The line stays fixed: voyager-browser expands by **reading more of what's already served**, never by *doing more to the server*. Anything active (submitting, fuzzing, probing) belongs to a separate consent-gated organ.
## The Voyager family
| Package | Sense |
| --- | --- |
| [`@dir-ai/voyager`](https://www.npmjs.com/package/@dir-ai/voyager) | web — verified-internet retrieval |
| **`@dir-ai/voyager-browser`** | **web page — observe one live URL** |
| [`@dir-ai/voyager-repo`](https://www.npmjs.com/package/@dir-ai/voyager-repo) | code — orient in a repository |
| [`@dir-ai/voyager-net`](https://www.npmjs.com/package/@dir-ai/voyager-net) | hosts — authorized host audit |
| [`@dir-ai/voyager-contract`](https://www.npmjs.com/package/@dir-ai/voyager-contract) | the cognitive contract the senses speak |
| [`@dir-ai/voyager-agent`](https://www.npmjs.com/package/@dir-ai/voyager-agent) | the one agent that composes them |
## License
MIT © dir-ai