jackwener / jackwener/OpenCLI

LinkedIn: browser-realm decodeLinkedInSafetyUrl accepts credentialed URLs that the Node-side helper rejects

Open
#2,352 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
29.3k
Forks
2.9k
Avg merge
15h 36m
Merged PRs (30d)
70

Description

## Summary

`decodeLinkedInSafetyUrl` exists in two realms with **different security postures for credential-bearing URLs**. The Node-side helper rejects `user:pass@` URLs; the three browser-realm (page-evaluate) copies do not, so credentialed targets — including via the `/safety/go/?url=` redirect — reach extraction output.

This is **pre-existing behaviour**, not introduced by #2351. It was found while reviewing that PR and deliberately kept out of scope, since #2351 was a pure Node-side consolidation and the browser strings were a hard negative boundary.

## Measured on current `main` (`de16476e`)

| input | Node (`shared.js`) | browser-realm |
|---|---|---|
| `https://user:pass@example.com/x` | `""` | `"https://user:pass@example.com/x"` |
| `/safety/go/?url=` | `""` | `"https://user:pass@evil.com/"` |
| `/in/someone` | `""` | `"https://www.linkedin.com/in/someone"` |
| `javascript:alert(1)` | `""` | `""` (consistent) |

## Why they differ

- **Node** (`clis/linkedin/shared.js`) routes through `normalizeHttpUrl`, which explicitly rejects `parsed.username || parsed.password`.
- **Browser** copies check only `protocol === 'http:' || 'https:'`. They cannot import `normalizeHttpUrl` (page realm) and resolve against `location.origin`.

Browser-realm copies on current main:
- `clis/linkedin/profile-experience.js:149` (extraction)
- `clis/linkedin/profile-experience.js:393` (dialog)
- `clis/linkedin/profile-projects.js:92` (extraction)

Note these are **not merely duplicated code** — they are realm-local implementations that cannot be replaced by a Node import (`normalizeWhitespace` is undefined in the page realm; `location` is undefined in Node), and they have a genuinely different relative-URL contract.

## Decision needed

Should browser-side extraction also reject credentialed URLs, matching the Node side?

- **If yes:** add a `username`/`password` check to all three page-realm copies, plus tests for credentials, `safety/go` redirect targets, and relative URLs.
- **If no:** document why extraction output may legitimately contain credentials, so the divergence is intentional rather than accidental.

Either way the **relative-URL divergence** (`/in/someone` → `""` vs origin-resolved) is entangled: aligning the realms touches that contract too, so it should be decided together rather than patching only the credential check.

The Node side's rejection is now pinned by `clis/linkedin/shared.test.js`, so one side of the divergence is test-protected regardless of the outcome.

Contributor guide

Open the contributing guide

Research direction

Start with the three browser-realm implementations at clis/linkedin/profile-experience.js:149 and :393 and clis/linkedin/profile-projects.js:92, then compare them with normalizeHttpUrl and clis/linkedin/shared.test.js. Decide the intended credential and relative-URL contract, then add or update coverage for credentials, safety/go redirects, and relative URLs so the browser behavior matches the decision.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
cli, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.