projectdiscovery/nuclei · warning

parse target: %w

Error message

parse target: %w

What it means

normalizeTarget failed at url.Parse: the target contains '://' but is not a parseable URL. Go's url.Parse rejects control characters in URLs, invalid percent-escapes ('%zz'), and malformed hosts such as an unclosed IPv6 bracket. The target string handed to a goexec-backed client (wmi.Client, etc.) is malformed rather than a plain host or host:port.

Source

Thrown at pkg/js/libs/goexec/target.go:18

package goexec

import (
	"fmt"
	"net"
	"net/url"
	"strings"
)

func normalizeTarget(target string) (string, error) {
	target = strings.TrimSpace(target)
	if target == "" {
		return "", ErrMissingTarget
	}
	if strings.Contains(target, "://") {
		parsed, err := url.Parse(target)
		if err != nil {
			return "", fmt.Errorf("parse target: %w", err)
		}
		target = parsed.Host
	}
	if host, port, err := net.SplitHostPort(target); err == nil {
		if host == "" {
			return "", ErrMissingTarget
		}
		if port == "" {
			return host, nil
		}
		return net.JoinHostPort(host, port), nil
	}
	if strings.HasPrefix(target, "[") && strings.HasSuffix(target, "]") {
		target = strings.TrimPrefix(strings.TrimSuffix(target, "]"), "[")
		if target == "" {
			return "", ErrMissingTarget
		}
	}

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Pass a plain host or host:port ('dc01', '10.0.0.5:445') with no scheme.
  2. Strip the scheme client-side: use new URL(target).host before constructing.
  3. Trim whitespace and reject control characters in targets before use.
  4. For IPv6, use bracketed host or host:port forms that net.SplitHostPort handles.

Example fix

// before
const c = new wmi.Client('smb://dc01 acme/', auth); // parse target: invalid control character / missing parts

// after
const raw = 'smb://dc01 acme/';
const host = new URL(raw.replace(/\s+/g, '')).host || new URL(raw.replace(/\s+/g, '')).hostname;
const c = new wmi.Client(host, auth);
Defensive patterns

Strategy: validation

Validate before calling

// normalize the target client-side before constructing wmi.Client
function toHostPort(target) {
  let t = String(target || '').trim();
  if (t.includes('://')) {
    const u = new URL(t); // throws on malformed URLs — catch early
    t = u.host || u.hostname;
  }
  if (/[-]/.test(t)) throw new Error('control characters in target');
  return t; // plain host or host:port
}
const safeTarget = toHostPort(rawTarget);

Type guard

/** @param {unknown} t @returns {boolean} */
function isParsableTarget(t) {
  if (typeof t !== 'string') return false;
  const s = t.trim();
  if (s === '' || /[-]/.test(s)) return false;
  if (!s.includes('://')) return true;
  try { new URL(s); return true; } catch (_) { return false; }
}

Prevention

When it happens

Trigger: new wmi.Client('smb://dc01 acme/', auth) (space in authority), 'https://[2001:db8::1' (missing ']'), control bytes from untrusted input lists, or '%zz' escape sequences — anything with a scheme separator that fails strict URL parsing.

Common situations: Templates concatenating unvalidated input into the target; IPv6 literals copied without brackets closure; copy-paste targets with whitespace or CR.

Related errors


AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15). Data as JSON: /api/errors/72b1137df8243304. Report an issue: GitHub.