Bitcoin Forum
May 12, 2026, 12:47:30 AM *
News: Latest Bitcoin Core release: 31.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: « 1 2 3 4 [5]  All
  Print  
Author Topic: Round#2 [OPEN] Omnisee 🚨 Bug Hunt Campaign – Help To Improve & Get Rewarded! 🐞  (Read 544 times)
irfan_pak10
Legendary
*
Offline

Activity: 3710
Merit: 1720


🧙‍♂️ #kycfree


View Profile WWW
May 08, 2026, 07:07:13 PM
 #81

/sitemap.xml lists only 10 latest blocks — site is invisible to search

Sitemap contains 11 <loc> entries: the homepage and the latest 10 blocks. No /address/{x}, no /tx/{x}, no /faq, no older blocks. For a Bitcoin explorer with hundreds of thousands of indexable pages, this means search engines see almost nothing.

Reproducer
Code:
$ curl -s https://omnisee.io/sitemap.xml | grep -c "<loc>"
11
 
$ curl -s https://omnisee.io/sitemap.xml | grep "<loc>" | head -3
<loc>https://omnisee.io/</loc>
<loc>https://omnisee.io/block/948314</loc>
<loc>https://omnisee.io/block/948313</loc>
   …only the latest 10 blocks…

Impact
•   Search engines miss /faq, popular addresses, recent transactions, older blocks.
•   SEO crawl budget is wasted re-discovering the same 10 latest blocks every visit.
•   Discoverability for the Tor mirror, the FAQ, the Asset-AI Detective explanations is zero.

Fix
Generate a paginated sitemap-index: sitemaps/blocks/{i}.xml, sitemaps/addresses/{i}.xml, sitemaps/transactions/{i}.xml. Include /faq and the Tor mirror. Cap each sub-sitemap at 50 000 URLs (the spec maximum).



ContentWriter
Member
**
Offline

Activity: 403
Merit: 15

Earn from your cryptocurrencies


View Profile
May 10, 2026, 01:23:24 PM
 #82

Report Title: Unsanitized external input stored and returned via API

Report Details: Starting with any address (I use the Silk Road one, but it could be your own or Satoshi’s Genesis address)

https://omnisee.io/api/address/1HQ3Go3ggs8pFnXuHVHRytPCq5fGG8Hbhx/scam-check

and querying the API, you get:

Code:
{
  "address": "1HQ3Go3ggs8pFnXuHVHRytPCq5fGG8Hbhx",
  "is_scam": true,
  "details": {
    "is_scam": true,
    "address": "1HQ3Go3ggs8pFnXuHVHRytPCq5fGG8Hbhx",
    "category": "sextortion",
    "risk_level": "high",
    "sources": [
      "chainabuse"
    ],
    "report_count": 5,
    "first_seen": "2026-03-27T20:45:09+00:00",
    "description": "ChainAbuse: {{7*7}} its for the test in bugcrowd",
    "ai_summary": "## Verdict\nSUSPICIOUS — address linked to sextortion scams, but no authoritative sanctions or law enforcement confirmation.\n\n## Key Factors\n- Flagged by multiple community reports (5) on ChainAbuse as a sextortion scam wallet.\n- On-chain activity shows high total received (208,210 BTC) with zero balance, consistent with a disposable collection address.\n- Mixing score indicates some coinjoin usage, possibly to obfuscate flow.\n\n## Activity Pattern\nAddress likely used to receive payments from sextortion email scams. Large volume suggests widespread targeting; funds have been moved out.\n\n## Recommendation\nMONITOR — while not confirmed by OFAC or major analytics firms, the pattern and multiple reports warrant caution. Interaction may expose users to legal or reputational risk."
  }
}

the line
Code:
"description": "ChainAbuse: {{7*7}} its for the test in bugcrowd"

This shows that the Chainabuse data has not been sanitized it would have returned 49. It is the log of a test carried out on Bugcrowd by someone else, and if it were rendered in HTML on the website. If this field is rendered in an HTML context without escaping, it could lead to Stored XSS.

Based on the bolded, it is compelling to state that there is no basis in "it would have returned 49". The reason for this is that   

Code:
{{7*7}}
is Angular/Handlebars syntax, not Python/Jinja2. This means that FastAPI doesn't evaluate it.
What would return 49: Jinja2/Flask template syntax (
Code:
{{7*7}}
in a template context), which is different from what Omnisee uses: FastAPI (Python), which returns
Code:
{{7*7}}
literally as a string

What I'm saying is that
Code:
{{7*7}}
would NOT evaluate to 49 in this situation, bearing in mind that it's just a string that someone else submitted to ChainAbuse.

Also bear in mind that stored XSS is unproven in this case.

This is a good bug find, just needed correcting the incorrect claims.

🔐 No KYC Crypto Trading
💸 Earn While You Trade
👉 Join Bridgoro Now
ContentWriter
Member
**
Offline

Activity: 403
Merit: 15

Earn from your cryptocurrencies


View Profile
May 10, 2026, 04:23:51 PM
 #83

MAJOR   TLSv1.0 and TLSv1.1 accepted on the edge

RFC 8996 (March 2021) deprecates TLSv1.0/1.1. Modern browsers refuse them, but legacy bots and downgrade-attack tooling still negotiate them. PCI-DSS, NIST SP 800-52r2 disallow them.

Reproducer
Code:
$ nmap --script ssl-enum-ciphers -p 443 omnisee.io | grep -E "TLSv1\.[01]"
| TLSv1.0:
| TLSv1.1:


Impact
•   Audit/compliance flag.
•   Legacy bots and TLS downgrade attacks remain possible.

Fix
Cloudflare → SSL/TLS → Edge Certificates → Minimum TLS Version → set to TLS 1.2 (or 1.3).




Report Title: Additional test cases and recommendations for /block/{invalid_format} handling

Report Details: I looked at this one and ran a few more tests. A couple of things are still missing.

First, there are other inputs worth checking. 0 is the genesis block and works fine. But floats like 1.5 or 3.14159 – those should be a straight 400. Right now they might be slipping through. Overflow numbers like 99999999999999999999 and 18446744073709551616 (that's 2^64) are also edge cases worth testing. A valid looking hash that doesn't actually exist should be 404, not something else. And mixed hex like 123abc456 – that's neither a height nor a real hash, so 400 is the right call.

The real problem here is that invalid input is hitting an unhandled exception and bubbling up as a 5xx. That's not great. The code is probably trying to parse whatever comes in without checking format first. So you get a crash on something that should have been rejected early.

The original report didn't mention a few practical things. First, monitoring will fire on every 503. Someone running a quick fuzz will fill your alert dashboard with noise. Those should be filtered out. Second, logging these as ERROR instead of WARN just adds clutter. It's a user typo, not a broken service. Third, rate limiting these paths would make fuzzing a lot harder.

A proper fix needs a regex for 64-char hex hashes, a sane max height (something like 10 million is safe), and a clear path: check height, then hash, then return 400. Upstream errors should never surface as 5xx. Wrap them and return 404.

Also worth noting, this same pattern is probably sitting in /api/block and /api/transaction as well. Would be good to audit all path parameters in one go.

The bottom line is if someone types garbage, you don't return a 5xx. That's the rule to enforce everywhere. Something like this should work pretty well:

Code:
import re

BLOCK_HASH_PATTERN = re.compile(r'^[0-9a-fA-F]{64}$')
MAX_HEIGHT = 10_000_000

@app.get("/block/{input}")
async def get_block(input: str):
    # Try height
    if input.isdigit():
        height = int(input)
        if height < 0 or height > MAX_HEIGHT:
            return {"error": "height out of range"}, 400
        try:
            result = fetch_by_height(height)
            return result if result else {"error": "not found"}, 404
        except:
            return {"error": "not found"}, 404
    
    # Try hash
    if BLOCK_HASH_PATTERN.match(input):
        try:
            result = fetch_by_hash(input)
            return result if result else {"error": "not found"}, 404
        except:
            return {"error": "not found"}, 404
    
    # Invalid format
    return {"error": "invalid block identifier"}, 400


🔐 No KYC Crypto Trading
💸 Earn While You Trade
👉 Join Bridgoro Now
ContentWriter
Member
**
Offline

Activity: 403
Merit: 15

Earn from your cryptocurrencies


View Profile
May 10, 2026, 05:00:39 PM
 #84

MAJOR   /api/transaction/{nonexistent_txid} returns 500 instead of 404

Valid 64-hex-format but nonexistent txids trigger an unhandled backend exception. API returns bare 'Internal Server Error' (text/plain, 21 bytes). The HTML route /tx/{nonexistent} correctly returns 200 with a 'Transaction Not Found' page — handlers diverge.

Reproducer
Code:
$ for tx in 1111...1111 ffff...ffff 0123...cdef 2cca...47ce; do
    curl https://omnisee.io/api/transaction/$tx
  done
[HTTP 500] tx=1111...      → "Internal Server Error"
[HTTP 500] tx=ffff...      → "Internal Server Error"
[HTTP 500] tx=0123...cdef  → "Internal Server Error"
[HTTP 500] tx=2cca...47ce  → "Internal Server Error"

Impact
•   Reveals an unhandled exception path on the API.
•   Wrong status code (500) confuses any client doing 'if 404 then ... else error' control flow.
•   Pollutes error metrics / SRE dashboards with fake outages.

Fix
Wrap the upstream provider call in try/except; return 404 + JSON {"error":"Transaction not found","code":"TX_NOT_FOUND"} when no provider returns the tx.




I tried to reproduce this but kept running into Cloudflare blocking me with 520 errors after just a couple requests. Couldn't get far enough to confirm if the 500 is still there. That said, there's a few things worth adding to this report.

First, the fix mentioned is solid but missing something. The API returns JSON for other errors like invalid format, but right now on 500 it's returning plain text. Whatever fix Omnisee implements should keep the response format consistent, ie JSON across the board, even for 404. Clients expecting JSON will break on plain text.

Second, worth checking how the HTML route
Code:
/tx/{nonexistent}
handles this. The reports says it returns 200 with a not-found page. That's okay for a browser but the API should stick to proper HTTP status codes. I believe that 200 for a missing resource is technically incorrect even if it works for humans.

The third issue is that the difference between API and HTML routes matters for anyone who would like to build tools on top of the Omnisee app. If an API client gets 500 today, they might retry or alert. But a 404 would tell them to stop immediately. The current behavior could cause unnecessary retries and false alarms.

One more thing, I suggest if someone can still test this, try edge cases like 63-character hex, 65-character hex, or valid length with non-hex characters like "zzz". Those should return 400. If they return 500 that's the same root cause.




🔐 No KYC Crypto Trading
💸 Earn While You Trade
👉 Join Bridgoro Now
Pages: « 1 2 3 4 [5]  All
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!