linode / linode/linode-cli

[Bug]: Incomplete URL substring sanitization Unvalidated Redirects and Forwards

Ouverte
#735 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

bug
Langage dominant
Python
Étoiles
442
Forks
159
Merge moyen
7 j 21 h
PR mergées (30 j)
8

Description

CLI Version

v5.56.2

Command

https://github.com/linode/linode-cli/blob/fafe73e1f48a48ab9cbdf9b01f679e041f6bf3fa/tests/integration/domains/test_slave_domains.py#L73-L73

Sanitizing untrusted URLs is a common technique for preventing attacks such as request forgeries and malicious redirections. Usually, this is done by checking that the host of a URL is in a set of allowed hosts. However, treating the URL as a string and checking if one of the allowed hosts is a substring of the URL is very prone to errors. Malicious URLs can bypass such security checks by embedding one of the allowed hosts in an unexpected location.

Even if the substring check is not used in a security-critical context, the incomplete check may still cause undesirable behaviors when the check succeeds accidentally.

Output

No response

Expected Behavior

Recommendation

Parse a URL before performing a check on its host value, and ensure that the check handles arbitrary subdomain sequences correctly.

Actual Behavior

CWE-20

Steps to Reproduce

POC

The following code checks that a URL redirection will reach the example.com domain.

from flask import Flask, request, redirect
from urllib.parse import urlparse

app = Flask(__name__)

# Not safe, as "evil-example.net/example.com" would be accepted

@app.route('/some/path/bad1')
def unsafe1(request):
    target = request.args.get('target', '')
    if "example.com" in target:
        return redirect(target)

# Not safe, as "benign-looking-prefix-example.com" would be accepted

@app.route('/some/path/bad2')
def unsafe2(request):
    target = request.args.get('target', '')
    if target.endswith("example.com"):
        return redirect(target)



#Simplest and safest approach is to use an allowlist

@app.route('/some/path/good1')
def safe1(request):
    allowlist = [
        "example.com/home",
        "example.com/login",
    ]
    target = request.args.get('target', '')
    if target in allowlist:
        return redirect(target)

#More complex example allowing sub-domains.

@app.route('/some/path/good2')
def safe2(request):
    target = request.args.get('target', '')
    host = urlparse(target).hostname
    #Note the '.' preceding example.com
    if host and host.endswith(".example.com"):
        return redirect(target)

The first two examples show unsafe checks that are easily bypassed. In unsafe1 the attacker can simply add example.com anywhere in the url. For example, http://evil-example.net/example.com. In unsafe2 the attacker must use a hostname ending in example.com, but that is easy to do. For example, http://benign-looking-prefix-example.com.

The second two examples show safe checks. In safe1, an allowlist is used. Although fairly inflexible, this is easy to get right and is most likely to be safe. In safe2, urlparse is used to parse the URL, then the hostname is checked to make sure it ends with .example.com.

References

SSRF
XSS Unvalidated Redirects and Forwards Cheat Sheet.
CWE-20.

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez par tests/integration/domains/test_slave_domains.py à la ligne 73 et suivez la gestion des URL qu’il met à l’épreuve. Vérifiez si la validation de l’hôte repose sur une correspondance de sous-chaînes, puis exécutez le test d’intégration concerné. C’est terminé lorsque des préfixes de nom d’hôte arbitraires ou du texte intégré correspondant à un hôte autorisé ne passent plus la validation, tandis que les hôtes autorisés légitimes continuent de fonctionner.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
cli, security
Type d'issue
Bug
Difficulté
3/5
Temps estimé
1-2 jours
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
45/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.