iOfficeAI/OfficeCLI · error · ArgumentException
Invalid {contextKey} URL scheme '{scheme}:': only http, http
Error message
Invalid {contextKey} URL scheme '{scheme}:': only http, https, mailto, ftp, ftps, sftp, news, tel, sms, file, about, and ppaction targets are accepted. javascript:, data:, vbscript:, and similar schemes are rejected to prevent click-bait redirection in shared documents. What it means
Thrown by HyperlinkUriValidator.RequireSafeScheme when an external hyperlink URL uses a URI scheme not in the allowlist (http, https, mailto, ftp, ftps, sftp, news, tel, sms, file, about, ppaction). The validator runs at write time to prevent dangerous schemes like javascript:, data:, and vbscript: from being embedded into shared Office documents where they could trigger script execution or data exfiltration on recipients. The check only applies to absolute URIs — handler-internal targets (slide://, fragment anchors, in-workbook refs) are resolved before the validator is consulted, so non-absolute URIs pass through silently.
Source
Thrown at src/officecli/Core/HyperlinkUriValidator.cs:85
/// URI whose scheme is in the allowlist. Used by the HTML preview, which
/// must not throw on an authored-in HYPERLINK() formula but also must not
/// emit a javascript:/data:/file: href as an XSS sink.
/// </summary>
public static bool IsSafeScheme(string url)
{
if (string.IsNullOrEmpty(url)) return false;
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri)) return false;
return !string.IsNullOrEmpty(uri.Scheme) && AllowedSchemes.Contains(uri.Scheme);
}
public static void RequireSafeScheme(string url, string contextKey = "link")
{
if (string.IsNullOrEmpty(url)) return;
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri)) return; // not absolute → handler-internal path, not our concern
var scheme = uri.Scheme;
if (string.IsNullOrEmpty(scheme)) return;
if (AllowedSchemes.Contains(scheme)) return;
throw new ArgumentException(
$"Invalid {contextKey} URL scheme '{scheme}:': only http, https, mailto, ftp, ftps, sftp, news, tel, sms, file, about, and ppaction targets are accepted. " +
"javascript:, data:, vbscript:, and similar schemes are rejected to prevent click-bait redirection in shared documents.");
}
}
View on GitHub (pinned to 1ced45e900)
Solutions
- Replace the disallowed scheme with an allowed one (http, https, mailto, ftp, ftps, sftp, news, tel, sms, file, about, ppaction) that serves the same intent.
- If the link is handler-internal navigation (e.g. PowerPoint slide jump), use the handler's internal notation (ppaction://, slide://, #anchor) which is resolved before the validator is consulted — do not pass it as an absolute external URI.
- If you are building a hyperlink from user input, sanitize or reject non-http(s)/mailto schemes upstream before calling Set/Add.
- For read-only inspection of an existing document's unsafe links, use query instead of set — the validator only fires on write operations.
Example fix
// before — rejected set path='/body/p[1]/r[1]' hyperlink='javascript:void(0)' // after — allowed set path='/body/p[1]/r[1]' hyperlink='https://example.com' // or for an email link: set path='/body/p[1]/r[1]' hyperlink='mailto:nobody@example.com'
Defensive patterns
Strategy: validation
Validate before calling
// Pre-validate scheme before calling Set/Add hyperlink
using OfficeCli.Core;
bool IsHyperlinkSafe(string url)
{
// Use the non-throwing predicate before the write
return HyperlinkUriValidator.IsSafeScheme(url);
}
// Or call RequireSafeScheme explicitly to fail before the handler is invoked
try { HyperlinkUriValidator.RequireSafeScheme(candidateUrl, "link"); }
catch (ArgumentException) { /* reject input, log, or sanitize */ } Try / catch
try
{
HyperlinkUriValidator.RequireSafeScheme(url, contextKey: "link");
handler.Set(path, new() { ["hyperlink"] = url });
}
catch (ArgumentException ex) when (ex.Message.Contains("URL scheme"))
{
// Log the rejected URL and continue without the hyperlink
Console.Error.WriteLine($"Rejected unsafe hyperlink: {url}");
} Prevention
- Always use the non-throwing IsSafeScheme predicate to pre-filter user-supplied URLs before passing them to Set/Add.
- When building hyperlinks programmatically, default to http/https and reject any input that doesn't start with a known-safe scheme prefix.
- If accepting user URLs in an agent pipeline, sanitize to http(s) only unless you have an explicit reason to allow mailto/tel/etc.
When it happens
Trigger: Calling any handler Set/Add operation that writes a hyperlink (e.g. set path='/body/p[1]/r[1]' hyperlink='javascript:alert(1)') with a URL whose scheme is not in AllowedSchemes. The RequireSafeScheme method is invoked after the URL has been classified as an external (absolute) URI. Passing 'data:text/html,...', 'vbscript:foo', or any custom scheme like 'myapp://' will trigger it. A null, empty, or non-absolute URI (relative path) does NOT trigger this — it returns early.
Common situations: Programmatic agents or LLM-generated batch scripts that construct hyperlink targets from untrusted user input or scraped HTML. Round-tripping a document that was originally authored by a tool that embeds javascript: or data: links. Copying a URL from a web page that uses data: URIs for inline assets. A dump→replay scenario where the source document contained a hyperlink with a scheme the validator rejects.
Related errors
- max_depth_exceeded
- Image file '{path}' has extension .{ext} but magic bytes ind
- Invalid skill file path: {relativePath}
- Refusing to fetch {what} from non-public address '{addr}' (h
- body too large
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/fe92e3d4ca9b6802.
Report an issue: GitHub.