AOSSIE-Org / AOSSIE-Org/Gitcord-GithubDiscordBot

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

Offen
#87 1 Kommentar 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
bug
Vorherrschende Sprache
Python
Sterne
22
Forks
21
Ø Merge
1 T. 20 Std.
Gemergte PRs (30 T.)
21

Beschreibung

### 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

Beitragsleitfaden

Beitragsleitfaden öffnen

Rechercherichtung

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.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
backend, security
Issue-Typ
Bug
Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Aktivitätsstatus
Aktiv
Klarheit
Klar beschrieben
Anfängerfreundlichkeit
85/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.