Make WordPress Core

Opened 8 years ago

Last modified 5 days ago

#46791 reopened defect (bug)

esc_url() adding http:// to a relative URL to parent directory '../pathname/'

Reported by: OrangePixelNath Owned by:
Priority: normal Milestone: Future Release
Component: Formatting Version: 5.1
Severity: normal Keywords: has-patch has-unit-tests has-test-info
Cc: Focuses:

Description

esc_url() adds 'http://' when it shouldn't.

Line 4191 wp-includes/formatting.php states

If the URL doesn't appear to contain a scheme, we presume it needs http:// prepended (unless a relative link starting with /, # or ? or a php file).

This is prepending http:// to a relative url to a parent directory i.e. ../path-to-page/

Funtion needs ../ adding to the array or some regex code.

Attachments (2)

46791.diff​ (633 bytes ) - added by subrataemfluence 7 years ago.
Proposed patch.
46791-2.diff​ (782 bytes ) - added by subrataemfluence 7 years ago.
Corrected patch.

Download all attachments as: .zip

Change History (16)

#1 @SergeyBiryukov
8 years ago

  • Component General → Formatting

@subrataemfluence
7 years ago

Proposed patch.

@subrataemfluence
7 years ago

Corrected patch.

#2 @OrangePixelNath
7 years ago

  • Resolution → worksforme
  • Status new → closed

#3 @OrangePixelNath
7 years ago

  • Keywords needs-patch added

#4 follow-up: @desrosj
7 years ago

  • Keywords has-patch added; needs-patch removed

@OrangePixelNath did you mean to close this ticket? If so, can you detail why? What did you discover that made your report incorrect or unnecessary?

#5 in reply to: ↑ 4 @OrangePixelNath
7 years ago

  • Resolution worksforme
  • Status closed → reopened

Replying to desrosj:

@OrangePixelNath did you mean to close this ticket? If so, can you detail why? What did you discover that made your report incorrect or unnecessary?

No sorry. I'm new to the system so didn't understand what was next.

#6 @desrosj
7 years ago

  • Keywords needs-testing added

No problem! That’s why I checked to be sure :)

Next, the ticket stays open for community members to text and review.

Last edited 7 years ago by desrosj (previous) (diff)

#7 @r1k0
8 months ago

  • Keywords needs-refresh added; needs-testing removed

The patch doesn't apply cleanly; it fails with the error:

Running "patch:46791" (patch) task
? Please select a patch to apply 46791-2.diff​ (782 bytes) - adde
d by subrataemfluence 7 years ago.
patching file wp-includes/formatting.php
Hunk #1 FAILED at 4190.
1 out of 1 hunk FAILED -- saving rejects to file wp-includes/formatting.php.rej

Patch needs a refresh and removing needs-testing.

This ticket was mentioned in ​PR #10849 on ​WordPress/wordpress-develop by ​@sabernhardt.


8 months ago
#8

  • Keywords has-unit-tests added; needs-refresh removed

Does not prepend the fallback protocol when the reference starts with a dot (./ or ../).

Trac 46791

#9 @sabernhardt
8 months ago

  • Milestone Awaiting Review → 7.0

#10 @sabernhardt
7 months ago

  • Milestone 7.0 → 7.1

Moving to the next release cycle.

This ticket was mentioned in ​Slack in #core by adrianduffell. ​View the logs.


3 months ago

#12 @khokansardar
3 months ago

  • Keywords has-test-info added

Patch testing report

Patch / PR tested

Environment

WordPress: 7.1-beta1-62760-src
PHP: 8.2.18 (Docker)
MySQL: 8.0.36 (Docker)
OS: macOS 26.5.2
Tested via: WP-CLI wp eval + PHPUnit (server-side formatting function, no UI)
Local wordpress-develop @ ​http://localhost:8889

Steps

  1. On trunk, call esc_url() with directory-relative references and observe the output.
  2. Apply PR #10849 and call esc_url() with the same inputs.
  3. Confirm non-relative inputs are unaffected (real domains, fragments, queries, scheme'd URLs).
  4. Run the escUrl PHPUnit test class.

Results

  • Bug on trunk: pass — esc_url('../parent-directory') returns http://../parent-directory (and ./, deep ../../../../ likewise get http:// prepended).
  • Fix, parent/current dir: pass — ../parent-directory, ./current-directory, ../../../../up-four-directories are returned unchanged.
  • Fix, ticket example: pass — esc_url('../path-to-page/') returns ../path-to-page/.
  • Relative with query/fragment: pass — ./a/b?x=1#y preserved.
  • No regression (real domain): pass — example.com still returns http://example.com.
  • No regression (other relatives / schemes): pass — /example.php, example.php, #fragment, ?foo=bar, http://example.com/, https://example.com/, ftp://x.com/ all unchanged.
  • Unit tests: pass — full escUrl class OK (19 tests, 129 assertions), including the updated test_relative() (7 assertions).

Conclusion
PR #10849 adds . to the array of first characters that mark a URL as a relative link in esc_url(), so ./ and ../ directory-relative references are no longer given a fallback http:// prefix. The change is minimal (a one-character functional edit plus a comment update) and well scoped to the ticket, with matching unit-test coverage. No backward-compatibility concern found: real domains and already-scheme'd URLs are unaffected. Minor note: any leading . is now treated as relative (e.g. .hidden stays .hidden), which is harmless since a hostname cannot begin with a bare dot. Recommend commit.

#13 @adrianduffell
3 months ago

  • Milestone 7.1 → Future Release

This was brought up in yesterday’s bug scrub and decided to punt.

@sabernhardt it looks like there are a few comments to address on the PR, and then this could probably land in the 7.2 cycle.

​qorud02 commented on ​PR #10849:


5 days ago
#14

Patch testing report

I tested the esc_url() source change from ​PR #10849 on WordPress 7.2-alpha-64042, PHP 8.4.26, Windows x64. The isolated installation uses SQLite 3.53.4 with SQLite Database Integration 1.8.0, Twenty Twenty-Five and no active regular plugins. This formatting function does not query the database.

I added coverage for an HTTPS-only protocol list, a Korean directory-relative path, and rejected schemes alongside the reported paths. I applied the public PR source hunk, checked that the source bytes changed, ran the same inputs in a fresh PHP process, and restored the original file. I did not run the PHPUnit suite.

Results with the default protocol list

Input Before After
../parent-directory http://../parent-directory ../parent-directory
./current-directory http://./current-directory ./current-directory
../../assets/cafe-menu.pdf?ver=1#menu http://../../assets/cafe-menu.pdf?ver=1#menu Input preserved
./한글/메뉴.html Incorrect http:// prefix Input preserved, including Korean characters
.well-known/security.txt Incorrect http:// prefix Input preserved
example.com http://example.com Same
/root/path, ?x=1, #top Input preserved Same
https://example.org/file.pdf Input preserved Same
javascript:alert(1) Empty string Same
data:text/html;base64,AA== Empty string Same
mailto:operator@example.org Input preserved Same

HTTPS-only protocol list

The following additional cases were called with esc_url( $input, array( 'https' ) ):

  • ../parent-directory and ./current-directory are preserved after the patch.
  • example.com still receives the https:// fallback.
  • Explicit http://example.org/ and javascript:alert(1) still return an empty string.

Result: the 18-case integration matrix confirms that relative paths are preserved with both the default and HTTPS-only lists, while domain fallback and scheme rejection continue to work in the tested cases.

Public PR diff SHA256: 962b9a7a3309e3ba87bc05d214415b752bd25a701568fe62fc8a8f80e8a07ca1.

WordPress.org username: kyunghan.

AI assistance: OpenAI Codex prepared and executed the scripts and helped draft this report. The before/after outputs were generated by the stated local WordPress installation.

Note: See TracTickets for help on using tickets.