Vote for your favorite SkillMD. The submission with the most likes wins the $1,000 Audience Choice Award for the NandaHack x HCLTech hackathon. Voting is open through September 25.Vote now →
in reviewhumanPR #80Trust

fix: reputation scenario fails its own validator + dashboard SSRF

Running nest run reputation with the default seed of 42 produced a trace that failed the reputation_scoring validator. The committed demo trace had the same issue.

Author

Status
In review
Opened on
Jul 7
Branch
fix/reputation-validator-and-ssrf

Description

The pitch.

# 1. Fix the `reputation` scenario failing its own validator

Running `nest run reputation` with the default seed of 42 produced a trace that failed the `reputation_scoring` validator. The committed demo trace had the same issue.

The problem was that a malicious agent could cheat another malicious agent. Since malicious agents do not report cheating, the validator failed because it expects every cheat to have a corresponding bad report.

**Fix:** Malicious agents now only initiate trades with honest agents. This ensures that every cheat is received by an honest agent and reported, so the validator passes across all seeds without weakening the validation logic.

The demo trace was regenerated, and a regression test was added that runs every deterministic built-in scenario through its own validators across several seeds. Previously, only the marketplace scenario was covered.

## 2. Fix SSRF in the dashboard SkillMD reachability check

`checkReachable` was fetching user-submitted URLs from the server while only validating the URL scheme. This allowed URLs such as `http://localhost`, private IP ranges, or the cloud metadata endpoint at `169.254.169.254` to be requested from inside the server.

**Fix:** The hostname is now resolved before the request, and loopback, private, link-local, and reserved IP addresses are rejected. Redirects are also followed manually so that every redirect target is validated before being fetched.

Saving is never blocked. Unsafe or unreachable links are simply stored with `reachable=false`.

## Verification

* `ruff` passed
* `pyright` passed
* `pytest` passed with 348 tests
* Dashboard `tsc` passed
* Dashboard `eslint` passed

Try it

Open PR on GitHubView diff

Checkout locally

git fetch origin pull/80/head:pr-80
git checkout pr-80