666ghj/MiroFish · critical · StarHistoryError

generated SVG contains an external resource

Error message

generated SVG contains an external resource

What it means

Raised by _validate_svg when an href attribute is present but the element is not an <image>, or its value is not one of the two pinned data URIs (OWNER_AVATAR_DATA_URI / WATERMARK_LOGO_DATA_URI). The published SVG must be fully self-contained: no external fetches, and the only embedded images are the byte-reviewed avatar and watermark.

Source

Thrown at scripts/star_history.py:1239

            if raw_name.startswith("{") or raw_name not in allowed_for_element:
                raise StarHistoryError("generated SVG contains a forbidden attribute")
            if (
                not value.isascii()
                or "\\" in value
                or "/*" in value
                or "*/" in value
                or any(ord(character) < 0x20 for character in value)
            ):
                raise StarHistoryError("generated SVG contains an unsafe attribute value")
            exact_values = exact_attribute_values.get(raw_name)
            if exact_values is not None and value not in exact_values:
                raise StarHistoryError("generated SVG contains an unsafe attribute value")
            if raw_name == "href":
                if local_name != "image" or value not in {
                    OWNER_AVATAR_DATA_URI,
                    WATERMARK_LOGO_DATA_URI,
                }:
                    raise StarHistoryError("generated SVG contains an external resource")
            lowered = value.lower().replace(" ", "")
            if "url(" in lowered and lowered not in {
                "url(#xkcdify)",
                "url(#clip-circle-title)",
            }:
                raise StarHistoryError("generated SVG contains an external resource")
            if lowered.startswith(("http:", "https:", "//")):
                raise StarHistoryError("generated SVG contains an external resource")
    if avatar_count != 1 or watermark_count != 1:
        raise StarHistoryError("generated SVG must contain both reviewed images")
    try:
        avatar = base64.b64decode(OWNER_AVATAR_BASE64, validate=True)
    except ValueError as exc:
        raise StarHistoryError("reviewed avatar data is invalid") from exc
    if (
        len(avatar) > MAX_INLINE_AVATAR_BYTES
        or hashlib.sha256(avatar).hexdigest() != OWNER_AVATAR_SHA256
        or _reviewed_avatar_dimensions(avatar) != OWNER_AVATAR_DIMENSIONS

View on GitHub (pinned to b5b53acc57)

Solutions

  1. Locate every href in the generated SVG (grep 'href=' static/image/star-history-*.svg) and confirm only the two <image> elements carry it.
  2. If replacing the avatar or watermark image, update the whole constant set together: OWNER_AVATAR_BASE64, OWNER_AVATAR_SHA256, OWNER_AVATAR_DIMENSIONS (or WATERMARK_LOGO_*), since the data URI is derived from the base64 constant.
  3. Remove <a>/external-link wrappers; this design intentionally forbids links inside the published SVG.
  4. If you need a new embedded image, extend the avatar/watermark pattern: pinned data URI + count check + hash check, never a bare allowlist entry.

Example fix

# before: external link added to the chart
<a href="https://github.com/owner/repo">...</a>

# after: keep the SVG link-free; put links in the README that embeds the SVG
# (no href elements other than the two reviewed <image> data URIs)
Defensive patterns

Strategy: validation

Validate before calling

def only_reviewed_hrefs(root) -> bool:
    for el in root.iter():
        href = el.get("href")
        if href is not None:
            if not el.tag.endswith("}image"):
                return False
            if href not in {OWNER_AVATAR_DATA_URI, WATERMARK_LOGO_DATA_URI}:
                return False
    return True

Try / catch

try:
    _validate_svg(svg_bytes)
except StarHistoryError as exc:
    if "external resource" in str(exc):
        # grep the SVG for href=/xlink:href and confirm only the two data URIs remain
        ...

Prevention

When it happens

Trigger: Adding any href (e.g. on <a>, <use>, <tspan>) other than on the two blessed <image> elements; changing the avatar/watermark image without regenerating the pinned DATA_URI constants; a template edit that swaps href for xlink:href-style external URLs; embedding a different logo PNG.

Common situations: Rebranding: someone replaces static assets or the owner avatar but only edits the SVG template, not OWNER_AVATAR_BASE64/SHA256 constants; adding a clickable link (<a href=...>) around the chart; pulling in an icon set that references external sprites.

Related errors


AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14). Data as JSON: /api/errors/5dfff3b6a85fd107. Report an issue: GitHub.