VYPR
High severityNVD Advisory· Published Feb 24, 2026· Updated Feb 26, 2026

New API has Potential XSS in its MarkdownRenderer component

CVE-2026-25802

Description

New API is a large language mode (LLM) gateway and artificial intelligence (AI) asset management system. Prior to version 0.10.8-alpha.9, a potential unsafe operation occurs in component MarkdownRenderer.jsx, allowing for Cross-Site Scripting(XSS) when the model outputs items containing `` tag. Version 0.10.8-alpha.9 fixes the issue.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

New API prior to 0.10.8-alpha.9 has a stored XSS vulnerability in MarkdownRenderer.jsx due to unsafe use of dangerouslySetInnerHTML.

Vulnerability

Overview

CVE-2026-25802 is a cross-site scripting (XSS) vulnerability in New API, an LLM gateway and AI asset management system. The flaw resides in the MarkdownRenderer.jsx component, which uses dangerouslySetInnerHTML to render AI-generated HTML content without sanitization [1][2]. This allows an attacker to inject arbitrary JavaScript, such as `` tags, into the rendered output.

Exploitation

An attacker can exploit this by crafting a prompt that causes the LLM to output to include a `` tag. For example, asking the model to write a script that redirects to an external site will result in the script being executed in the user's browser when the response is rendered in the playground [2]. The attack requires no special privileges beyond access to the playground interface, and the malicious script is stored in the chat history, meaning it will re-execute every time the page is loaded [2].

Impact

Successful exploitation leads to arbitrary JavaScript execution in the context of the victim's session. This can be used to steal session cookies, perform actions on behalf of the user, or redirect to phishing pages. The stored nature of the XSS makes it particularly dangerous, as users cannot easily remove the malicious content from their history [2].

Mitigation

The issue is fixed in version 0.10.8-alpha.9. The fix introduces an escapeHtml function and sanitizes AI-generated HTML before rendering, preventing script injection [4]. Users should upgrade immediately. As a workaround, the advisory, the vendor suggests rendering previews in an iframe sandbox or purifying dangerous HTML strings [2].

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/QuantumNous/new-apiGo
< 0.10.8-alpha.90.10.8-alpha.9

Affected products

2
  • Range: <0.10.8-alpha.9
  • QuantumNous/new-apiv5
    Range: < 0.10.8-alpha.9

Patches

1
ab5456eb1049

🔒 fix(security): sanitize AI-generated HTML to prevent XSS in playground

2 files changed · +82 16
  • web/src/components/common/markdown/MarkdownRenderer.jsx+44 1 modified
    @@ -93,6 +93,49 @@ export function Mermaid(props) {
       );
     }
     
    +function SandboxedHtmlPreview({ code }) {
    +  const iframeRef = useRef(null);
    +  const [iframeHeight, setIframeHeight] = useState(150);
    +
    +  useEffect(() => {
    +    const iframe = iframeRef.current;
    +    if (!iframe) return;
    +
    +    const handleLoad = () => {
    +      try {
    +        const doc = iframe.contentDocument || iframe.contentWindow?.document;
    +        if (doc) {
    +          const height =
    +            doc.documentElement.scrollHeight || doc.body.scrollHeight;
    +          setIframeHeight(Math.min(Math.max(height + 16, 60), 600));
    +        }
    +      } catch {
    +        // sandbox restrictions may prevent access, that's fine
    +      }
    +    };
    +
    +    iframe.addEventListener('load', handleLoad);
    +    return () => iframe.removeEventListener('load', handleLoad);
    +  }, [code]);
    +
    +  return (
    +    <iframe
    +      ref={iframeRef}
    +      sandbox='allow-same-origin'
    +      srcDoc={code}
    +      title='HTML Preview'
    +      style={{
    +        width: '100%',
    +        height: `${iframeHeight}px`,
    +        border: 'none',
    +        overflow: 'auto',
    +        backgroundColor: '#fff',
    +        borderRadius: '4px',
    +      }}
    +    />
    +  );
    +}
    +
     export function PreCode(props) {
       const ref = useRef(null);
       const [mermaidCode, setMermaidCode] = useState('');
    @@ -227,7 +270,7 @@ export function PreCode(props) {
               >
                 HTML预览:
               </div>
    -          <div dangerouslySetInnerHTML={{ __html: htmlCode }} />
    +          <SandboxedHtmlPreview code={htmlCode} />
             </div>
           )}
         </>
    
  • web/src/components/playground/CodeViewer.jsx+38 15 modified
    @@ -91,22 +91,45 @@ const codeThemeStyles = {
       },
     };
     
    +const escapeHtml = (str) => {
    +  return str
    +    .replace(/&/g, '&amp;')
    +    .replace(/</g, '&lt;')
    +    .replace(/>/g, '&gt;')
    +    .replace(/"/g, '&quot;')
    +    .replace(/'/g, '&#039;');
    +};
    +
     const highlightJson = (str) => {
    -  return str.replace(
    -    /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g,
    -    (match) => {
    -      let color = '#b5cea8';
    -      if (/^"/.test(match)) {
    -        color = /:$/.test(match) ? '#9cdcfe' : '#ce9178';
    -      } else if (/true|false|null/.test(match)) {
    -        color = '#569cd6';
    -      }
    -      return `<span style="color: ${color}">${match}</span>`;
    -    },
    -  );
    +  const tokenRegex =
    +    /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g;
    +
    +  let result = '';
    +  let lastIndex = 0;
    +  let match;
    +
    +  while ((match = tokenRegex.exec(str)) !== null) {
    +    // Escape non-token text (structural chars like {, }, [, ], :, comma, whitespace)
    +    result += escapeHtml(str.slice(lastIndex, match.index));
    +
    +    const token = match[0];
    +    let color = '#b5cea8';
    +    if (/^"/.test(token)) {
    +      color = /:$/.test(token) ? '#9cdcfe' : '#ce9178';
    +    } else if (/true|false|null/.test(token)) {
    +      color = '#569cd6';
    +    }
    +    // Escape token content before wrapping in span
    +    result += `<span style="color: ${color}">${escapeHtml(token)}</span>`;
    +    lastIndex = tokenRegex.lastIndex;
    +  }
    +
    +  // Escape remaining text
    +  result += escapeHtml(str.slice(lastIndex));
    +  return result;
     };
     
    -const linkRegex = /(https?:\/\/[^\s<"'\]),;}]+)/g;
    +const linkRegex = /(https?:\/\/(?:[^\s<"'\]),;&}]|&amp;)+)/g;
     
     const linkifyHtml = (html) => {
       const parts = html.split(/(<[^>]+>)/g);
    @@ -184,14 +207,14 @@ const CodeViewer = ({ content, title, language = 'json' }) => {
     
       const highlightedContent = useMemo(() => {
         if (contentMetrics.isVeryLarge && !isExpanded) {
    -      return displayContent;
    +      return escapeHtml(displayContent);
         }
     
         if (isJsonLike(displayContent, language)) {
           return highlightJson(displayContent);
         }
     
    -    return displayContent;
    +    return escapeHtml(displayContent);
       }, [displayContent, language, contentMetrics.isVeryLarge, isExpanded]);
     
       const renderedContent = useMemo(() => {
    

Vulnerability mechanics

Synthesis attempt was rejected by the grounding validator. Re-run pending.

References

5

News mentions

0

No linked articles in our index yet.