{"record":{"id":"c66b35d0ddde36bd","repo":"jackwener/OpenCLI","slug":"label-must-be-an-https-linkedin-url-without-cre","errorCode":null,"errorMessage":"${label} must be an https LinkedIn URL without credentials or port","messagePattern":"(.+?) must be an https LinkedIn URL without credentials or port","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/shared.js","lineNumber":97,"sourceCode":"export function looksLinkedInAuthWall(value) {\n  const text = normalizeWhitespace(value).toLowerCase();\n  if (!text) return false;\n  return /linkedin\\.com\\/(?:login|checkpoint|authwall|uas)/i.test(text)\n    || /\\b(sign in|log in|join linkedin|captcha|verification required)\\b/i.test(text)\n    || /(请登录|登录领英|安全验证)/.test(text);\n}\n\nexport function assertSafeLinkedinUrl(value, label, fallbackPath = '/') {\n  const raw = normalizeWhitespace(value || `https://www.linkedin.com${fallbackPath}`);\n  let parsed;\n  try {\n    parsed = new URL(raw, 'https://www.linkedin.com');\n  } catch {\n    throw new ArgumentError(`${label} must be a LinkedIn URL`);\n  }\n  const host = parsed.hostname.toLowerCase();\n  if (parsed.protocol !== 'https:' || parsed.username || parsed.password || parsed.port) {\n    throw new ArgumentError(`${label} must be an https LinkedIn URL without credentials or port`);\n  }\n  if (host !== 'linkedin.com' && host !== 'www.linkedin.com') {\n    throw new ArgumentError(`${label} must point to linkedin.com`);\n  }\n  return parsed.toString();\n}\n\nexport function requireStringArg(args, key, label = key) {\n  const value = normalizeWhitespace(args?.[key]);\n  if (!value) throw new ArgumentError(`${label} is required`);\n  return value;\n}\n\nexport function parseLimit(value, fallback, max) {\n  if (value === undefined || value === null || value === '') return fallback;\n  const parsed = Number(value);\n  if (!Number.isInteger(parsed) || parsed < 1 || parsed > max) {\n    throw new ArgumentError(`--limit must be an integer between 1 and ${max}`);","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/shared.js#L79-L115","documentation":"After parsing succeeds, assertSafeLinkedinUrl enforces transport hardening: the URL must use https, and must not embed username/password credentials or a non-default port. Violating any of these raises this ArgumentError, preventing SSRF-style abuse and credential leakage in URLs handed to the scraper.","triggerScenarios":"Passing http:// instead of https://; embedding credentials (https://user:pass@linkedin.com/...); specifying an explicit port (https://www.linkedin.com:8443/in/me/) — any of these triggers the check `protocol !== 'https:' || username || password || port`.","commonSituations":"Constructing URLs from templates that default to http; pasting URLs that include basic-auth credentials for a proxy; local dev proxy setups that append :port and are mistakenly reused for LinkedIn args.","solutions":["Use plain https URLs without credentials or ports: https://www.linkedin.com/in/<handle>/.","Strip credentials/port before calling: new URL(raw); u.protocol='https:'; u.username=u.password=''; u.port=''.","If you need a proxy, configure it at the HTTP-client/browser level, not in the URL."],"exampleFix":"// before\nawait runCommand('linkedin services-read', ['--profile-url', 'http://user:pw@www.linkedin.com:8443/in/jane/']);\n// after\nawait runCommand('linkedin services-read', ['--profile-url', 'https://www.linkedin.com/in/jane-doe/']);","handlingStrategy":"validation","validationCode":"function sanitizeLinkedInUrl(raw) {\n  const u = new URL(String(raw).trim(), 'https://www.linkedin.com');\n  u.protocol = 'https:'; u.username = ''; u.password = ''; u.port = '';\n  return u.toString();\n}\nargs['profile-url'] = sanitizeLinkedInUrl(args['profile-url']);","typeGuard":"function isHardenedHttpsUrl(v) {\n  try {\n    const u = new URL(String(v));\n    return u.protocol === 'https:' && !u.username && !u.password && !u.port;\n  } catch { return false; }\n}","tryCatchPattern":null,"preventionTips":["Never embed credentials or ports in LinkedIn URLs; configure proxies at the client level.","Normalize http:// links to https:// before passing them.","Add a startup lint that flags non-https or credentialed URLs in config."],"tags":["linkedin","argument-validation","url","security"],"backgroundTag":"invalid-url-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}