router-for-me/CLIProxyAPI · error

plugin store url contains sensitive query parameter

Error message

plugin store url contains sensitive query parameter

What it means

hasSensitiveQueryParameter detected a query parameter in the store URL whose name looks like credential material (e.g. token, api_key, signature patterns). validatePluginStoreRequestURL blocks this because secrets in query strings get recorded in proxies, access logs, and caches. Authentication material must go through the auth rules instead of the URL.

Source

Thrown at internal/pluginstore/auth.go:319

			return false, fmt.Errorf("plugin store resolved auth header value is empty")
		}
		headers.Set(item.HeaderName, string(item.HeaderValue))
	default:
		return false, fmt.Errorf("unsupported plugin store resolved auth type %q", item.Type)
	}
	return true, nil
}

func validatePluginStoreRequestURL(auth []AuthConfig, requestURL string, kind string) error {
	parsed, errParse := url.Parse(strings.TrimSpace(requestURL))
	if errParse != nil || parsed.Scheme == "" || parsed.Host == "" {
		return fmt.Errorf("invalid plugin store url")
	}
	if parsed.User != nil {
		return fmt.Errorf("plugin store url must not contain credentials")
	}
	if hasSensitiveQueryParameter(parsed) {
		return fmt.Errorf("plugin store url contains sensitive query parameter")
	}
	if strings.EqualFold(parsed.Scheme, "http") && !allowInsecurePluginStoreURL(auth, requestURL, kind) {
		return fmt.Errorf("insecure plugin store url requires matching allow-insecure auth rule")
	}
	return nil
}

func allowInsecurePluginStoreURL(auth []AuthConfig, requestURL string, kind string) bool {
	item, ok := matchingAuthConfig(auth, requestURL, kind)
	return ok && item.AllowInsecure
}

func validateResolvedAuthExpiry(auth []ResolvedAuthConfig, expiresAt time.Time, now time.Time, requestURL string, kind string) error {
	if expiresAt.IsZero() {
		return nil
	}
	if _, ok := matchingResolvedAuthConfig(auth, requestURL, kind); !ok {
		return nil

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Strip the sensitive query parameter from the URL
  2. Move the secret into an auth rule (type: bearer with token-env, or header) matching that store
  3. If the parameter is genuinely non-sensitive, rename it to something not on the sensitive list

Example fix

# before
url: https://plugins.example.com/index.json?api_key=sk-123

# after
url: https://plugins.example.com/index.json
auth:
  - match: https://plugins.example.com
    type: bearer
    token-env: PLUGIN_API_KEY
Defensive patterns

Strategy: validation

Validate before calling

func urlHasSensitiveQuery(raw string) bool {
	u, err := url.Parse(strings.TrimSpace(raw))
	if err != nil {
		return false
	}
	for k := range u.Query() {
		lk := strings.ToLower(k)
		if strings.Contains(lk, "token") || strings.Contains(lk, "key") || strings.Contains(lk, "secret") || strings.Contains(lk, "signature") {
			return true
		}
	}
	return false
}

Prevention

When it happens

Trigger: A store URL containing ?token=..., ?api_key=..., ?access_token=... (or similar sensitive names) is used for a registry/metadata/artifact fetch.

Common situations: Copy-pasting a pre-signed or personal URL from a vendor dashboard; custom store that documents token-in-query auth; older config carried over after this hardening check was introduced.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/a37db0833cff1659. Report an issue: GitHub.