Skip to content

Commit 6c47085

Browse files
committed
fix: explore pole/antimeridian output + entropy read cap (audit findings)
Final adversarial security+correctness audit of the new modules: 0 Critical/ High (SSRF, untrusted-data crash, key leak all ruled out; TLS verified). Fixed: - explore_cast (MEDIUM): at lat=±90 cos(lat)->0 emitted target.lon ~1.9e14. Clamp the projection latitude (±89.9) and normalize output lon to [-180,180). - entropy (LOW): cap resp.read(1<<20) so a misbehaving endpoint can't stream an unbounded body. - tests/test_explore.py (+6, 1001->1007): pole/antimeridian regression — target finite, in [-180,180], within radius.
1 parent 7a5acd5 commit 6c47085

3 files changed

Lines changed: 33 additions & 3 deletions

File tree

scripts/entropy.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ def _fetch_quantum_bytes(n: int, timeout: float = 6.0) -> bytes | None:
4848
f"{_ANU_LEGACY_URL}?length={n}&type=uint8"
4949
)
5050
with urllib.request.urlopen(req, timeout=timeout) as resp: # noqa: S310
51-
payload = json.loads(resp.read().decode("utf-8"))
51+
# Cap the read: a compromised/misbehaving endpoint ignoring length=
52+
# must not stream an unbounded body into memory.
53+
payload = json.loads(resp.read(1 << 20).decode("utf-8"))
5254
if payload.get("success") and isinstance(payload.get("data"), list):
5355
data = bytes(int(b) & 0xFF for b in payload["data"])
5456
return data[:n] if len(data) >= n else None

scripts/explore_cast.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@
2828
from utils import json_print
2929

3030
EARTH_M_PER_DEG = 111_320.0 # metres per degree of latitude (mean)
31+
MAX_PROJ_LAT = 89.9 # clamp for the cos(lat) longitude projection
32+
33+
34+
def _cos_lat(lat: float) -> float:
35+
"""cos(latitude) clamped away from the poles so the longitude projection
36+
never explodes (cos -> 0 at ±90 would blow dx/(cos) up to ~1e14)."""
37+
return math.cos(math.radians(max(-MAX_PROJ_LAT, min(MAX_PROJ_LAT, lat))))
38+
39+
40+
def _norm_lon(lon: float) -> float:
41+
"""Wrap longitude into [-180, 180)."""
42+
return ((lon + 180.0) % 360.0) - 180.0
3143

3244
# 后天八卦 -> compass bearing (degrees, 0=N clockwise).
3345
BAGUA_BEARING: dict[str, float] = {
@@ -46,7 +58,7 @@
4658
def random_points(lat: float, lon: float, radius_m: float, n: int, rng):
4759
"""n uniformly-distributed points within radius_m of (lat, lon)."""
4860
pts = []
49-
cos_lat = math.cos(math.radians(lat)) or 1e-9
61+
cos_lat = _cos_lat(lat) or 1e-9
5062
for _ in range(n):
5163
r = radius_m * math.sqrt(rng.random()) # sqrt for uniform area
5264
theta = 2 * math.pi * rng.random()
@@ -62,7 +74,7 @@ def find_anomaly(pts, origin, radius_m, mode, grid=16):
6274
being grid-density, not gaussian KDE). Returns (target_lat, target_lon, z)."""
6375
olat, olon = origin
6476
span = radius_m / EARTH_M_PER_DEG # half-extent in degrees lat
65-
cos_lat = math.cos(math.radians(olat)) or 1e-9
77+
cos_lat = _cos_lat(olat) or 1e-9
6678
span_lon = span / cos_lat
6779

6880
if mode == "blindspot":
@@ -193,6 +205,8 @@ def main(argv: list[str] | None = None) -> int:
193205
rng = entropy.get_rng(args.seed, args.entropy)
194206
pts = random_points(args.lat, args.lon, args.radius, n, rng)
195207
tlat, tlon, z = find_anomaly(pts, (args.lat, args.lon), args.radius, args.mode)
208+
tlat = max(-90.0, min(90.0, tlat))
209+
tlon = _norm_lon(tlon)
196210

197211
dist = haversine_m(args.lat, args.lon, tlat, tlon)
198212
brg = bearing_deg(args.lat, args.lon, tlat, tlon)

tests/test_explore.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,20 @@ def test_determinism_with_seed():
3636
assert a["target"] == b["target"]
3737

3838

39+
@pytest.mark.parametrize("lat,lon", [
40+
(90, 0), (-90, 0), (89.95, 10), (0, 179.999), (0, -180), (0, 180),
41+
])
42+
def test_pole_and_antimeridian_output_finite_and_in_range(lat, lon):
43+
"""REGRESSION: at the poles cos(lat)->0 used to emit target.lon ~1.9e14;
44+
near ±180 the lon must wrap into range. Target must stay sane + in radius."""
45+
d = run("--lat", lat, "--lon", lon, "--radius", 2000, "--seed", 1)
46+
assert d["ok"] is True
47+
t = d["target"]
48+
assert -90.0 <= t["lat"] <= 90.0
49+
assert -180.0 <= t["lon"] <= 180.0
50+
assert d["distance_m"] <= 2000.1
51+
52+
3953
def test_entropy_and_safety_and_disclaimer_present():
4054
d = run("--lat", 1.0, "--lon", 1.0, "--seed", 3)
4155
assert d["entropy"]["source"] == "seed"

0 commit comments

Comments
 (0)