Skip to content

feat: add KURI_ALLOW_PRIVATE env var to bypass SSRF private-IP block#174

Open
thetrebor wants to merge 2 commits into
justrach:mainfrom
thetrebor:main
Open

feat: add KURI_ALLOW_PRIVATE env var to bypass SSRF private-IP block#174
thetrebor wants to merge 2 commits into
justrach:mainfrom
thetrebor:main

Conversation

@thetrebor

Copy link
Copy Markdown

Set KURI_ALLOW_PRIVATE=1 (or =true) to allow kuri to connect to localhost, 127.0.0.1, ::1, private IPv4 ranges (10/8, 172.16/12, 192.168/16), private IPv6 ranges (::1, fe80::/10, fc00::/7), and metadata/link-local IPs (169.254.x.x, 100.100.100.200).

Previously these addresses were unconditionally blocked by the SSRF validator. The new env var gates the entire private-IP check block, making it opt-in for local development and testing.

Changes:

  • src/crawler/validator.zig — wrap all private-IP/localhost/metadata checks in a !allow_private guard
  • src/crawler/validator.zig — add comprehensive tests for each address category with KURI_ALLOW_PRIVATE set to '1' and 'true'
  • readme.md — document KURI_ALLOW_PRIVATE in the env var table
  • CHANGELOG.md — add Unreleased section with feature entry
  • .gitignore — add zig-pkg/ build output directory

Copilot AI review requested due to automatic review settings June 1, 2026 17:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds an escape hatch for SSRF protections to ease local development/testing by allowing localhost and private/metadata IP targets when an environment variable is set.

Changes:

  • Add KURI_ALLOW_PRIVATE env var to bypass localhost/private/metadata IP blocking in validateUrl.
  • Add Zig tests validating the bypass behavior via environment manipulation.
  • Document the new env var in readme.md and CHANGELOG.md, and ignore zig-pkg/.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 4 comments.

File Description
src/crawler/validator.zig Adds KURI_ALLOW_PRIVATE logic and tests to bypass SSRF host/IP blocks
readme.md Documents KURI_ALLOW_PRIVATE in configuration table
CHANGELOG.md Notes new KURI_ALLOW_PRIVATE feature under Unreleased
.gitignore Ignores zig-pkg/ directory
Comments suppressed due to low confidence (1)

readme.md:1

  • The implementation also bypasses metadata IP blocking (169.254.169.254 and 100.100.100.200) when KURI_ALLOW_PRIVATE is enabled, but the README description only mentions localhost/private IPs. Update the docs to explicitly include metadata IPs to avoid a misleading security posture.
<p align="center">

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/crawler/validator.zig
Comment on lines +25 to 47
// KURI_ALLOW_PRIVATE=1 bypasses localhost and private-IP checks for local dev/testing.
const allow_private = if (compat.getenv("KURI_ALLOW_PRIVATE")) |val|
std.mem.eql(u8, val, "1") or std.mem.eql(u8, val, "true")
else
false;

if (!allow_private) {
if (isLocalhostAlias(host) or std.mem.eql(u8, host, "127.0.0.1") or std.mem.eql(u8, host, "::1")) {
return ValidationError.LocalhostBlocked;
}

if (isMetadataIpv4(host) or std.mem.eql(u8, host, "100.100.100.200")) {
return ValidationError.MetadataIpBlocked;
}
if (isMetadataIpv4(host) or std.mem.eql(u8, host, "100.100.100.200")) {
return ValidationError.MetadataIpBlocked;
}

if (isPrivateIpv4(host)) {
return ValidationError.PrivateIp;
}
if (isPrivateIpv4(host)) {
return ValidationError.PrivateIp;
}

if (isPrivateIpv6(host)) {
return ValidationError.PrivateIp;
if (isPrivateIpv6(host)) {
return ValidationError.PrivateIp;
}
}
Comment thread src/crawler/validator.zig
Comment on lines +351 to +352
extern "c" fn setenv(name: [*:0]const u8, value: [*:0]const u8, overwrite: c_int) c_int;
extern "c" fn unsetenv(name: [*:0]const u8) c_int;
Comment thread src/crawler/validator.zig
Comment on lines +354 to +370
const env_set = struct {
fn set(name: []const u8, value: []const u8) void {
var name_buf: [256]u8 = undefined;
var value_buf: [256]u8 = undefined;
@memcpy(name_buf[0..name.len], name);
name_buf[name.len] = 0;
@memcpy(value_buf[0..value.len], value);
value_buf[value.len] = 0;
_ = setenv(name_buf[0..name.len :0], value_buf[0..value.len :0], 1);
}
fn unset(name: []const u8) void {
var name_buf: [256]u8 = undefined;
@memcpy(name_buf[0..name.len], name);
name_buf[name.len] = 0;
_ = unsetenv(name_buf[0..name.len :0]);
}
};
Comment thread CHANGELOG.md
## [Unreleased]

### Features
- **`KURI_ALLOW_PRIVATE` env var** — set `KURI_ALLOW_PRIVATE=1` or `=true` to bypass the SSRF localhost and private-IP block. Useful for local development and testing where kuri needs to reach servers on localhost or private networks.
@thetrebor thetrebor mentioned this pull request Jun 1, 2026
@thetrebor thetrebor force-pushed the main branch 4 times, most recently from 153968b to 84668df Compare June 1, 2026 17:59
Set KURI_ALLOW_PRIVATE=1 (or =true) to allow kuri to connect to
localhost, 127.0.0.1, ::1, private IPv4 ranges (10/8, 172.16/12,
192.168/16), private IPv6 ranges (::1, fe80::/10, fc00::/7), and
metadata/link-local IPs (169.254.x.x, 100.100.100.200).

Previously these addresses were unconditionally blocked by the SSRF
validator. The new env var gates the entire private-IP check block,
making it opt-in for local development and testing.

Changes:
- src/crawler/validator.zig — wrap all private-IP/localhost/metadata
  checks in a !allow_private guard
- src/crawler/validator.zig — add comprehensive tests for each
  address category with KURI_ALLOW_PRIVATE set to '1' and 'true'
- readme.md — document KURI_ALLOW_PRIVATE in the env var table
- CHANGELOG.md — add Unreleased section with feature entry
- .gitignore — add zig-pkg/ build output directory
Major improvements to the pi-kuri Pi extension:

- Retry wrapper: CDP-fragile endpoints (page/info, screenshot,
  evaluate, text, markdown, links) auto-retry up to 3 times
  with exponential backoff on transient 502 failures.
- settle_ms param on kuri_screenshot: configurable settle delay
  before capture for heavy JS pages.
- Auto tab_id resolution: kuri_markdown and kuri_links now
  auto-discover the current session tab when none is provided.
- kuri_text fallback: if raw text extraction returns empty,
  falls back to aria-label traversal of interactive elements.
- kuri_console_errors: new diagnostic tool that intercepts
  console.error/warn and returns the last 30 entries for
  diagnosing broken pages.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants