Skip to content

Cryptographically randomise referal.generate_random_string #196

Description

@YaronZaki
  • Difficulty: good-first-issue · Effort: XS · Impact: every referral link

  • Problem Statement
    quantara/web_app/api/referal.py line 54 reads:

    def generate_random_string(length=16):
        return "".join(random.choices(string.ascii_letters + string.digits, k=length))

    Python's random is the Mersenne-Twister-based stream and is not
    cryptographically secure
    . Knowing the previous 624 outputs of
    random.choices, the rest of the stream is mathematically recoverable
    in O(2¹⁹) work. Today nothing else emits Mersenne bits so the stream
    is unobserved, but the moment another random call exists elsewhere in
    the request path (a future randomize_*() helper is foreseeable) the
    seed state widens.

  • Why It Matters
    Referral codes propagate via DMs, links, QR codes, social media. Their
    predictability is a social-engineering foothold: an attacker who can
    guess the codes mints tomorrow's valid referral codes for known
    wallet_ids, hijacking referrals en masse.

  • Expected Outcome
    A 16-character alphanumeric code generated from secrets.choice over a
    62-symbol alphabet, with key input via secrets.token_bytes.

  • Acceptance Criteria

    • Cross-product distribution test (10k draws) yields each char with frequency 1/62 ± 0.5%.
    • Hypothesis test against uniform random distribution p > 0.99.
    • secrets.token_bytes is the source; random.random / random.choices not invoked anywhere in the function.
    • No measurable entropy loss (≥ 95 bits for 16 alphanumeric chars).
  • Implementation Notes

    import secrets
    ALPHABET = string.ascii_letters + string.digits
    
    def generate_random_string(length: int = 16) -> str:
        return "".join(secrets.choice(ALPHABET) for _ in range(length))

    For higher performance under load, derive from secrets.token_bytes once:

    def generate_random_string(length=16):
        raw = secrets.token_bytes(length)  # unbiased as long as 256 >= len(ALPHABET); here 256 > 62
        return "".join(ALPHABET[b % len(ALPHABET)] for b in raw)
  • Files / Modules Affected

    • quantara/web_app/api/referal.py
    • quantara/web_app/tests/test_create_referal_link.py
  • Dependencies: standalone.

Metadata

Metadata

Assignees

No one assigned

    Labels

    GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26bugSomething isn't workingpriority/P1Imported from PRODUCTION_ISSUES.mdsecurity

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions