# BytesUtil.compare returns wrong result on some strings longer than 32 characters

BytesUtils.compare masks trailing bytes only for strings under 32 chars, so comparing long strings with shorter lengths yields wrong ordering, breaking DNS name comparison.

- Payout: Contest reward
- Severity: medium
- Program: ENS
- Credited: panprog
- Disclosed: 2022-12-13
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-07-ens-findings/issues/78
- Library page: https://bugbountylibrary.com/r/c4%3A2022-07-ens%3AM-04
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:accounting-error

**Target:** DNSSEC oracle Solidity library (BytesUtils.compare / RRUtils.compareNames)
**Root cause:** The mask condition only applies when shortest-idx < 32, so in the final loop pass for strings longer than 32 bytes, bytes beyond the provided length are not masked out and are wrongly included in comparison; the mask formula also overflows when shortest > 32.
**Steps:**
1. Compare first 33 chars of `01234567890123450123456789012345ab` vs `01234567890123450123456789012345aa`; expected equal, returns >.
2. Compare 33 chars of first string vs all 34 of second; expected <, returns >.
3. Apply gist patch and run `yarn test test/dnssec-oracle/TestSolidityTests.js` to observe failing dnsCompare on the two example .eth names.
**How found:** Code review of the masking logic in BytesUtils.compare, noticing the condition only handles the sub-32-byte case and reasoning about the final loop pass for longer strings.
**Insight:** When auditing length-bounded comparison/masking loops, check the final partial-chunk iteration separately: conditions written for the common short case often skip masking on the last pass for long inputs, and mask arithmetic can overflow when the bound exceeds the chunk size.
