AOSSIE-Org / AOSSIE-Org/Gitcord-GithubDiscordBot

[BUG]: Phishing URL injection via improper hostname validation in LinkedInProfileValidator

Aperta
#87 1 commento 0 reazioni 0 assegnatari Vedi su GitHub
bug
Lingua principale
Python
Stelle
22
Fork
21
Merge medio
1g 20h
PR unite (30g)
21

Descrizione

### Description
`LinkedInProfileValidator` (`src/ghdcbot/core/social_validators.py`) me hostname validation missing hai. Validator sirf check karta hai ke URL me `/in/` maujood hai ya nahi, lekin yeh verify nahi karta ke domain `linkedin.com` hai.

## Impact
* **Severity:** High (CWE-20: Improper Input Validation, CWE-601: URL Redirection to Untrusted Site)
* **Attack Scenario:** An attacker links a malicious credential-harvesting site (e.g. `https://evil-phishing.com/in/target`) via `/connect-social platform:LinkedIn profile:https://evil-phishing.com/in/target`.
* **Public Visibility:** The URL is displayed in Discord `/profile` embeds, where community members may trust and click it as a verified LinkedIn profile.
---
## Technical Details & Root Cause
In `src/ghdcbot/core/social_validators.py`:
```python
@staticmethod
def _normalize_url(url: str) -> str:
url = url.strip()

# Ensure https
if url.startswith("http://"):
url = "https://" + url[7:]
elif not url.startswith("https://"):
url = "https://" + url

# Remove www if present (normalize to linkedin.com)
url = url.replace("www.linkedin.com", "linkedin.com")

# Remove trailing slashes and query params
url = url.split("?")[0].rstrip("/")

# Reject company pages
if "/company/" in url or "/companies/" in url or "/school/" in url:
raise ValueError("Company and school pages are not supported, only personal profiles")

# Must be in /in/ path for personal profiles
if "/in/" not in url:
raise ValueError("Only LinkedIn profile URLs (linkedin.com/in/...) are supported")

return url
Key Flaws:
No Hostname Check: The validator relies purely on string manipulation (.replace("www.linkedin.com", "linkedin.com")) and a substring check (if "/in/" not in url:).
Inconsistency with other validators: In contrast, XProfileValidator uses urllib.parse.urlparse to strictly assert:
python

if host in {"x.com", "twitter.com"}:
Spoofing Vulnerability: URLs such as https://linkedin.com.attacker.com/in/victim or https://evil-phishing.com/in/victim pass _normalize_url and _extract_profile_id.
Exception Handling: Rejection currently relies on downstream Pydantic model initialization, which raises an unhandled pydantic_core.ValidationError rather than a clean, user-friendly ValueError expected by the command handler.

### Steps to Reproduce

from ghdcbot.core.social_validators import LinkedInProfileValidator

validator = LinkedInProfileValidator()
normalized = validator._normalize_url("https://evil-phishing.com/in/target")
profile_id = validator._extract_profile_id("https://evil-phishing.com/in/target")

print("Normalized:", normalized) # Output: https://evil-phishing.com/in/target
print("Profile ID:", profile_id) # Output: target

## Proposed Fix

### 1. In `src/ghdcbot/core/social_validators.py` (`LinkedInProfileValidator`):
- Parse the URL using `urllib.parse.urlparse`.
- Validate that the scheme is `http` or `https` (and canonicalize to `https://`).
- Extract `hostname`, strip leading `www.`, and enforce that it strictly matches `linkedin.com`.
- Validate that the path strictly matches `/in/`.
- Raise clean `ValueError` exceptions with descriptive error messages.

### 2. In `tests/test_social_validators.py`:
- Add unit tests verifying rejection of:
- `https://evil-phishing.com/in/target`
- `https://linkedin.com.attacker.org/in/target`
- `https://fake-linkedin.com/in/target`
- Malicious schemes (e.g., `javascript:`, `ftp:`)

---

## Acceptance Criteria
- [ ] `LinkedInProfileValidator.validate()` rejects non-LinkedIn domains containing `/in/`.
- [ ] Subdomain spoofing (e.g. `linkedin.com.attacker.com`) is rejected with a `ValueError`.
- [ ] Valid LinkedIn formats (`https://linkedin.com/in/user`, `https://www.linkedin.com/in/user`, `linkedin.com/in/user`) continue to pass.
- [ ] All test suites pass cleanly (`pytest tests/test_social_validators.py`).

### Logs and Screenshots

_No response_

### Environment Details

_No response_

### Impact

High - Major feature is broken

### Code of Conduct

- [x] I have joined the [Discord server](https://discord.gg/hjUhu33uAn) and will post updates there
- [x] I have searched existing issues to avoid duplicates

Guida per i contributori

Apri la guida per i contributori

Direzione di ricerca

Start in src/ghdcbot/core/social_validators.py, reading LinkedInProfileValidator and the existing XProfileValidator hostname checks. Run pytest tests/test_social_validators.py, then cover the listed spoofed domains and malicious schemes while preserving the accepted LinkedIn URL formats. Done means invalid hosts and schemes raise ValueError and the targeted test suite passes.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
python
Ambito
backend, security
Tipo di issue
Bug
Difficoltà
3/5
Tempo stimato
1-2 giorni
Stato di attività
Attiva
Chiarezza
Specificata chiaramente
Idoneità per principianti
85/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.