VYPR
Medium severity4.2NVD Advisory· Published Jun 22, 2024· Updated Apr 29, 2026

CVE-2024-21517

CVE-2024-21517

Description

This affects versions of the package opencart/opencart from 4.0.0.0. A reflected XSS issue was identified in the redirect parameter of customer account/login route. An attacker can inject arbitrary HTML and Javascript into the page response. As this vulnerability is present in the account functionality it could be used to target and attack customers of the OpenCart shop. Notes: 1) The fix for this vulnerability is incomplete

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
opencart/opencartPackagist
>= 4.0.0.0

Affected products

1

Patches

1
0fd1ee4b6c94

added login to comment

https://github.com/opencart/opencartDaniel KerrJan 5, 2024via ghsa
7 files changed · +42 36
  • upload/catalog/controller/account/login.php+9 3 modified
    @@ -77,7 +77,7 @@ public function index(): void {
     
     			unset($this->session->data['redirect']);
     		} elseif (isset($this->request->get['redirect'])) {
    -			$data['redirect'] = urldecode($this->request->get['redirect']);
    +			$data['redirect'] = $this->request->get['redirect'];
     		} else {
     			$data['redirect'] = '';
     		}
    @@ -186,9 +186,15 @@ public function login(): void {
     
     			$this->model_account_customer->deleteLoginAttempts($this->request->post['email']);
     
    +			if (isset($this->request->post['redirect'])) {
    +				$redirect = urldecode($this->request->post['redirect']);
    +			} else {
    +				$redirect = '';
    +			}
    +
     			// Added strpos check to pass McAfee PCI compliance test (http://forum.opencart.com/viewtopic.php?f=10&t=12043&p=151494#p151295)
    -			if (isset($this->request->post['redirect']) && str_starts_with(html_entity_decode($this->request->post['redirect'], ENT_QUOTES, 'UTF-8'), $this->config->get('config_url'))) {
    -				$json['redirect'] = html_entity_decode($this->request->post['redirect'], ENT_QUOTES, 'UTF-8') . '&customer_token=' . $this->session->data['customer_token'];
    +			if ($redirect && str_starts_with($redirect, $this->config->get('config_url'))) {
    +				$json['redirect'] = $redirect . '&customer_token=' . $this->session->data['customer_token'];
     			} else {
     				$json['redirect'] = $this->url->link('account/account', 'language=' . $this->config->get('config_language') . '&customer_token=' . $this->session->data['customer_token'], true);
     			}
    
  • upload/catalog/controller/cms/comment.php+13 7 modified
    @@ -37,7 +37,7 @@ public function index(): string {
     		}
     
     		$data['logged'] = $this->customer->isLogged();
    -		$data['login'] = $this->url->link('account/login', 'language=' . $this->config->get('config_language'));
    +		$data['login'] = $this->url->link('account/login', 'language=' . $this->config->get('config_language') . '&page=' . $page . '&redirect=' . urlencode($this->url->link('cms/blog.info', 'language=' . $this->config->get('config_language') . '&article_id=' . $data['article_id'], true)));
     
     		$this->session->data['comment_token'] = oc_token(32);
     
    @@ -180,7 +180,7 @@ public function getList(): string {
     		$data['refresh'] = $this->url->link('cms/comment.list', 'language=' . $this->config->get('config_language') . '&article_id=' . $article_id . '&page=' . $page, true);
     
     		$data['logged'] = $this->customer->isLogged();
    -
    +		$data['login'] = $this->url->link('account/login', 'language=' . $this->config->get('config_language') . '&redirect=' . urlencode($this->url->link('cms/blog.info', 'language=' . $this->config->get('config_language') . '&article_id=' . $article_id, true)));
     
     		return $this->load->view('cms/comment_list', $data);
     	}
    @@ -420,10 +420,20 @@ public function rating(): void {
     			$article_comment_id = 0;
     		}
     
    +		if (isset($this->request->get['rating'])) {
    +			$rating = (bool)$this->request->get['rating'];
    +		} else {
    +			$rating = 0;
    +		}
    +
     		if (!isset($this->request->get['comment_token']) || !isset($this->session->data['comment_token']) || $this->request->get['comment_token'] != $this->session->data['comment_token']) {
     			$json['error'] = $this->language->get('error_token');
     		}
     
    +		if (!$this->customer->isLogged()) {
    +			$json['error'] = $this->language->get('error_login');
    +		}
    +
     		$this->load->model('cms/article');
     
     		$article_info = $this->model_cms_article->getArticle($article_id);
    @@ -439,16 +449,12 @@ public function rating(): void {
     			$json['error'] = $this->language->get('error_article_comment');
     		}
     
    -		if (!$this->customer->isLogged() && !$this->config->get('config_comment_guest')) {
    -			$json['error'] = $this->language->get('error_login');
    -		}
    -
     		if (!$json) {
     			// Anti-Spam
     			$rating_data = $this->request->post + [
     				'article_comment_id' => $article_comment_id,
     				'customer_id'        => $this->customer->getId(),
    -				'rating'             => (bool)$this->request->get['rating'],
    +				'rating'             => $rating,
     				'ip'                 => $this->request->server['REMOTE_ADDR']
     			];
     
    
  • upload/catalog/controller/startup/seo_url.php+3 3 modified
    @@ -81,10 +81,10 @@ public function rewrite(string $link): string {
     		$paths = [];
     
     		// Parse the query into its separate parts
    -		$parts = explode('&', $url_info['query']);
    +		$queries = explode('&', $url_info['query']);
     
    -		foreach ($parts as $part) {
    -			$pair = explode('=', $part);
    +		foreach ($queries as $query) {
    +			$pair = explode('=', $query);
     
     			if (isset($pair[0])) {
     				$key = (string)$pair[0];
    
  • upload/catalog/view/template/account/login.twig+3 3 modified
    @@ -38,12 +38,12 @@
                     <input type="password" name="password" value="{{ password }}" placeholder="{{ entry_password }}" id="input-password" class="form-control mb-1"/>
                     <a href="{{ forgotten }}">{{ text_forgotten }}</a>
                   </div>
    -              <div class="text-end">
    -                <button type="submit" class="btn btn-primary">{{ button_login }}</button>
    -              </div>
                   {% if redirect %}
                     <input type="hidden" name="redirect" value="{{ redirect }}"/>
                   {% endif %}
    +              <div class="text-end">
    +                <button type="submit" class="btn btn-primary">{{ button_login }}</button>
    +              </div>
                 </form>
               </div>
             </div>
    
  • upload/catalog/view/template/cms/comment_list.twig+8 16 modified
    @@ -2,40 +2,32 @@
       {% if comments %}
         {% for comment in comments %}
           <div id="comment-{{ comment.article_comment_id }}" class="border mb-3">
    -
             <div class="p-2">
               <p>{{ text_by }} {{ comment.author }} - {{ comment.date_added }}</p>
               <p>{{ comment.comment }}</p>
               <div class="text-end">
    -
    -            <button type="button" value="{{ comment.like }}" data-oc-toggle="rate" class="btn btn-secondary"><i class="fa fa-thumbs-up"></i></button>
    -            <button type="button" value="{{ comment.dislike }}" data-oc-toggle="rate" class="btn btn-secondary"><i class="fa fa-thumbs-down"></i></button>
    -
    -            {% if comment_guest %}
    +            {% if logged %}
    +              <button type="button" value="{{ comment.like }}" data-oc-toggle="rate" class="btn btn-secondary"><i class="fa fa-thumbs-up"></i></button>
    +              <button type="button" value="{{ comment.dislike }}" data-oc-toggle="rate" class="btn btn-secondary"><i class="fa fa-thumbs-down"></i></button>
                   <button type="button" value="{{ comment.reply_add }}" data-oc-toggle="comment" data-oc-target="#reply-{{ comment.article_comment_id }}" data-oc-trigger="#button-refresh-{{ comment.article_comment_id }}" class="btn btn-secondary">{{ button_reply }}</button>
                 {% else %}
    -              <button type="button" class="btn btn-secondary" disabled="disabled">{{ button_reply }}</button>
    +              <a href="{{ login }}" class="btn btn-secondary"><i class="fa fa-thumbs-up"></i></a>
    +              <a href="{{ login }}" class="btn btn-secondary"><i class="fa fa-thumbs-down"></i></a>
    +              <a href="{{ login }}" class="btn btn-secondary">{{ button_login_reply }}</a>
                 {% endif %}
    -
               </div>
             </div>
    -
             <div id="reply-{{ comment.article_comment_id }}">
    -
               <div id="reply-{{ comment.article_comment_id }}-0"></div>
    -
               <div class="text-center p-2 border-top">
    -            <button type="button" value="{{ comment.reply }}" id="button-refresh-{{ comment.article_comment_id }}" data-oc-toggle="refresh" data-oc-target="#reply-{{ comment.article_comment_id }}-0" class="btn btn-secondary"><i class="fa fa-sync"></i></button>
    -
    +            <button type="button" value="{{ comment.reply }}" id="button-refresh-{{ comment.article_comment_id }}" data-oc-toggle="refresh" data-oc-target="#reply-{{ comment.article_comment_id }}-0" class="btn btn-secondary d-none"><i class="fa fa-sync"></i></button>
                 {% if comment.reply_total %}
                   <button type="button" value="{{ comment.reply }}" data-oc-toggle="next" class="btn btn-secondary">{{ button_replies }} ({{ comment.reply_total }})</button>
                 {% else %}
                   <button type="button" class="btn btn-secondary" disabled>{{ button_replies }}</button>
                 {% endif %}
    -
               </div>
             </div>
    -
           </div>
         {% endfor %}
         <div class="row">
    @@ -47,7 +39,7 @@
       {% endif %}
     </div>
     <div class="text-center p-2">
    -  <button type="button" value="{{ refresh }}" id="button-refresh" data-oc-toggle="refresh" data-oc-target="#comment-0" class="btn btn-secondary"><i class="fa fa-sync"></i></button>
    +  <button type="button" value="{{ refresh }}" id="button-refresh" data-oc-toggle="refresh" data-oc-target="#comment-0" class="btn btn-secondary d-none"><i class="fa fa-sync"></i></button>
     </div>
     
     
    
  • upload/catalog/view/template/cms/comment_reply.twig+1 1 modified
    @@ -9,7 +9,7 @@
       </div>
     {% endif %}
     <div class="text-center p-2 border-top">
    -  <button type="button" value="{{ refresh }}" id="button-refresh-{{ parent_id }}" data-oc-toggle="refresh" data-oc-target="#reply-{{ parent_id }}-{{ page }}" class="btn btn-secondary"><i class="fa fa-sync"></i></button>
    +  <button type="button" value="{{ refresh }}" id="button-refresh-{{ parent_id }}" data-oc-toggle="refresh" data-oc-target="#reply-{{ parent_id }}-{{ page }}" class="btn btn-secondary d-none"><i class="fa fa-sync"></i></button>
       {% if not replies %}
         <button type="button" class="btn btn-secondary" disabled>{{ button_replies }}</button>
       {% elseif next %}
    
  • upload/catalog/view/template/cms/comment.twig+5 3 modified
    @@ -1,10 +1,12 @@
     <div class="text-center">
    -  <button type="button" value="{{ like }}" id="input-rating-like" data-oc-toggle="rate" class="btn btn-secondary"><i class="fa fa-thumbs-up"></i></button>
    -  <button type="button" value="{{ dislike }}" id="input-rating-dislike" data-oc-toggle="rate" class="btn btn-secondary"><i class="fa fa-thumbs-down"></i></button>
       {% if logged %}
    +    <button type="button" value="{{ like }}" id="input-rating-like" data-oc-toggle="rate" class="btn btn-secondary"><i class="fa fa-thumbs-up"></i></button>
    +    <button type="button" value="{{ dislike }}" id="input-rating-dislike" data-oc-toggle="rate" class="btn btn-secondary"><i class="fa fa-thumbs-down"></i></button>
         <button type="button" value="{{ comment_add }}" data-oc-toggle="comment" data-oc-target="#comment-0" data-oc-trigger="#button-refresh" class="btn btn-secondary">{{ button_comment }}</button>
       {% else %}
    -    <a href="" class="btn btn-secondary">{{ button_login }}</a>
    +    <a href="{{ login }}" class="btn btn-secondary"><i class="fa fa-thumbs-up"></i></a>
    +    <a href="{{ login }}" class="btn btn-secondary"><i class="fa fa-thumbs-down"></i></a>
    +    <a href="{{ login }}" class="btn btn-secondary">{{ button_login }}</a>
       {% endif %}
     </div>
     <hr/>
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.