VYPR
Critical severityNVD Advisory· Published Apr 23, 2021· Updated Aug 3, 2024

block repositories using http by default

CVE-2021-26291

Description

Apache Maven will follow repositories that are defined in a dependency’s Project Object Model (pom) which may be surprising to some users, resulting in potential risk if a malicious actor takes over that repository or is able to insert themselves into a position to pretend to be that repository. Maven is changing the default behavior in 3.8.1+ to no longer follow http (non-SSL) repository references by default. More details available in the referenced urls. If you are currently using a repository manager to govern the repositories used by your builds, you are unaffected by the risks present in the legacy behavior, and are unaffected by this vulnerability and change to default behavior. See this link for more information about repository management: https://maven.apache.org/repository-management.html

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Apache Maven by default follows insecure HTTP repositories from dependency POMs, allowing MITM attacks; fixed in 3.8.1 by blocking external HTTP repositories by default.

Vulnerability

Apache Maven will follow custom repositories defined in a dependency's Project Object Model (POM), including repositories using HTTP (non-SSL) connections. This behavior may surprise users who assume only trusted repositories are used. A malicious actor who takes over such a repository or performs a man-in-the-middle (MITM) attack can serve malicious artifacts. All versions prior to 3.8.1 are affected by this default behavior. [1][3]

Exploitation

An attacker needs to either gain control of a repository referenced in a dependency's POM (e.g., by registering an abandoned domain) or intercept network traffic between the build process and the repository. No additional user interaction is required beyond the standard build. The attacker can then inject arbitrary artifacts into the build, which will be downloaded and executed. [3]

Impact

Successful exploitation allows an attacker to execute arbitrary code within the context of the Maven build. This can lead to full compromise of the build system, including access to source code, credentials, and the ability to tamper with build artifacts (supply chain attack). [3]

Mitigation

Update to Apache Maven 3.8.1 or later, released on 2021-04-23. This version introduces a new mirror selector external:http:* that blocks all external HTTP repositories by default. The default conf/settings.xml includes this mirror configuration. Users who deploy a repository manager (e.g., Nexus, Artifactory) to govern repositories used by builds are unaffected and do not need to change their configuration. No other workarounds are available. [3][4]

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.apache.maven:maven-compatMaven
< 3.8.13.8.1
org.apache.maven:maven-coreMaven
< 3.8.13.8.1

Affected products

6

Patches

2
fa79cb22e456

[MNG-7116] add support for mirrorOf external:http:*

https://github.com/apache/mavenHervé BoutemyMar 13, 2021via ghsa
2 files changed · +89 10
  • maven-compat/src/main/java/org/apache/maven/repository/DefaultMirrorSelector.java+45 6 modified
    @@ -41,6 +41,8 @@ public class DefaultMirrorSelector
     
         private static final String EXTERNAL_WILDCARD = "external:*";
     
    +    private static final String EXTERNAL_HTTP_WILDCARD = "external:http:*";
    +
         public Mirror getMirror( ArtifactRepository repository, List<Mirror> mirrors )
         {
             String repoId = repository.getId();
    @@ -68,9 +70,14 @@ public Mirror getMirror( ArtifactRepository repository, List<Mirror> mirrors )
         }
     
         /**
    -     * This method checks if the pattern matches the originalRepository. Valid patterns: * =
    -     * everything external:* = everything not on the localhost and not file based. repo,repo1 = repo
    -     * or repo1 *,!repo1 = everything except repo1
    +     * This method checks if the pattern matches the originalRepository. Valid patterns:
    +     * <ul>
    +     * <li>{@code *} = everything,</li>
    +     * <li>{@code external:*} = everything not on the localhost and not file based,</li>
    +     * <li>{@code external:http:*} = any repository not on the localhost using HTTP,</li>
    +     * <li>{@code repo,repo1} = {@code repo} or {@code repo1},</li>
    +     * <li>{@code *,!repo1} = everything except {@code repo1}.</li>
    +     * </ul>
          *
          * @param originalRepository to compare for a match.
          * @param pattern used for match. Currently only '*' is supported.
    @@ -115,6 +122,12 @@ else if ( EXTERNAL_WILDCARD.equals( repo ) && isExternalRepo( originalRepository
                         result = true;
                         // don't stop processing in case a future segment explicitly excludes this repo
                     }
    +                // check for external:http:*
    +                else if ( EXTERNAL_HTTP_WILDCARD.equals( repo ) && isExternalHttpRepo( originalRepository ) )
    +                {
    +                    result = true;
    +                    // don't stop processing in case a future segment explicitly excludes this repo
    +                }
                     else if ( WILDCARD.equals( repo ) )
                     {
                         result = true;
    @@ -136,8 +149,34 @@ static boolean isExternalRepo( ArtifactRepository originalRepository )
             try
             {
                 URL url = new URL( originalRepository.getUrl() );
    -            return !( url.getHost().equals( "localhost" ) || url.getHost().equals( "127.0.0.1" )
    -                            || url.getProtocol().equals( "file" ) );
    +            return !( isLocal( url.getHost() ) || url.getProtocol().equals( "file" ) );
    +        }
    +        catch ( MalformedURLException e )
    +        {
    +            // bad url just skip it here. It should have been validated already, but the wagon lookup will deal with it
    +            return false;
    +        }
    +    }
    +
    +    private static boolean isLocal( String host )
    +    {
    +        return "localhost".equals( host ) || "127.0.0.1".equals( host );
    +    }
    +
    +    /**
    +     * Checks the URL to see if this repository refers to a non-localhost repository using HTTP.
    +     *
    +     * @param originalRepository
    +     * @return true if external.
    +     */
    +    static boolean isExternalHttpRepo( ArtifactRepository originalRepository )
    +    {
    +        try
    +        {
    +            URL url = new URL( originalRepository.getUrl() );
    +            return ( "http".equalsIgnoreCase( url.getProtocol() ) || "dav".equalsIgnoreCase( url.getProtocol() )
    +                || "dav:http".equalsIgnoreCase( url.getProtocol() )
    +                || "dav+http".equalsIgnoreCase( url.getProtocol() ) ) && !isLocal( url.getHost() );
             }
             catch ( MalformedURLException e )
             {
    @@ -146,7 +185,7 @@ static boolean isExternalRepo( ArtifactRepository originalRepository )
             }
         }
     
    -    static boolean matchesLayout( ArtifactRepository repository, Mirror mirror )
    +   static boolean matchesLayout( ArtifactRepository repository, Mirror mirror )
         {
             return matchesLayout( RepositoryUtils.getLayout( repository ), mirror.getMirrorOfLayouts() );
         }
    
  • maven-core/src/main/java/org/apache/maven/bridge/MavenRepositorySystem.java+44 4 modified
    @@ -710,6 +710,8 @@ public ArtifactRepository createLocalRepository( MavenExecutionRequest request,
     
         private static final String EXTERNAL_WILDCARD = "external:*";
     
    +    private static final String EXTERNAL_HTTP_WILDCARD = "external:http:*";
    +
         public static Mirror getMirror( ArtifactRepository repository, List<Mirror> mirrors )
         {
             String repoId = repository.getId();
    @@ -737,8 +739,14 @@ public static Mirror getMirror( ArtifactRepository repository, List<Mirror> mirr
         }
     
         /**
    -     * This method checks if the pattern matches the originalRepository. Valid patterns: * = everything external:* =
    -     * everything not on the localhost and not file based. repo,repo1 = repo or repo1 *,!repo1 = everything except repo1
    +     * This method checks if the pattern matches the originalRepository. Valid patterns:
    +     * <ul>
    +     * <li>{@code *} = everything,</li>
    +     * <li>{@code external:*} = everything not on the localhost and not file based,</li>
    +     * <li>{@code external:http:*} = any repository not on the localhost using HTTP,</li>
    +     * <li>{@code repo,repo1} = {@code repo} or {@code repo1},</li>
    +     * <li>{@code *,!repo1} = everything except {@code repo1}.</li>
    +     * </ul>
          *
          * @param originalRepository to compare for a match.
          * @param pattern used for match. Currently only '*' is supported.
    @@ -782,6 +790,12 @@ else if ( EXTERNAL_WILDCARD.equals( repo ) && isExternalRepo( originalRepository
                         result = true;
                         // don't stop processing in case a future segment explicitly excludes this repo
                     }
    +                // check for external:http:*
    +                else if ( EXTERNAL_HTTP_WILDCARD.equals( repo ) && isExternalHttpRepo( originalRepository ) )
    +                {
    +                    result = true;
    +                    // don't stop processing in case a future segment explicitly excludes this repo
    +                }
                     else if ( WILDCARD.equals( repo ) )
                     {
                         result = true;
    @@ -803,8 +817,34 @@ static boolean isExternalRepo( ArtifactRepository originalRepository )
             try
             {
                 URL url = new URL( originalRepository.getUrl() );
    -            return !( url.getHost().equals( "localhost" ) || url.getHost().equals( "127.0.0.1" )
    -                            || url.getProtocol().equals( "file" ) );
    +            return !( isLocal( url.getHost() ) || url.getProtocol().equals( "file" ) );
    +        }
    +        catch ( MalformedURLException e )
    +        {
    +            // bad url just skip it here. It should have been validated already, but the wagon lookup will deal with it
    +            return false;
    +        }
    +    }
    +
    +    private static boolean isLocal( String host )
    +    {
    +        return "localhost".equals( host ) || "127.0.0.1".equals( host );
    +    }
    +
    +    /**
    +     * Checks the URL to see if this repository refers to a non-localhost repository using HTTP.
    +     *
    +     * @param originalRepository
    +     * @return true if external.
    +     */
    +    static boolean isExternalHttpRepo( ArtifactRepository originalRepository )
    +    {
    +        try
    +        {
    +            URL url = new URL( originalRepository.getUrl() );
    +            return ( "http".equalsIgnoreCase( url.getProtocol() ) || "dav".equalsIgnoreCase( url.getProtocol() )
    +                || "dav:http".equalsIgnoreCase( url.getProtocol() )
    +                || "dav+http".equalsIgnoreCase( url.getProtocol() ) ) && !isLocal( url.getHost() );
             }
             catch ( MalformedURLException e )
             {
    
899465aeec03

[MNG-7117] add support for blocked mirror

https://github.com/apache/mavenHervé BoutemyMar 13, 2021via ghsa
3 files changed · +16 3
  • maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java+2 2 modified
    @@ -177,8 +177,8 @@ else if ( request.isUpdateSnapshots() )
             DefaultMirrorSelector mirrorSelector = new DefaultMirrorSelector();
             for ( Mirror mirror : request.getMirrors() )
             {
    -            mirrorSelector.add( mirror.getId(), mirror.getUrl(), mirror.getLayout(), false, mirror.getMirrorOf(),
    -                                mirror.getMirrorOfLayouts() );
    +            mirrorSelector.add( mirror.getId(), mirror.getUrl(), mirror.getLayout(), false, mirror.isBlocked(),
    +                                mirror.getMirrorOf(), mirror.getMirrorOfLayouts() );
             }
             session.setMirrorSelector( mirrorSelector );
     
    
  • maven-settings/pom.xml+1 1 modified
    @@ -46,7 +46,7 @@ under the License.
             <groupId>org.codehaus.modello</groupId>
             <artifactId>modello-maven-plugin</artifactId>
             <configuration>
    -          <version>1.1.0</version>
    +          <version>1.2.0</version>
               <models>
                 <model>src/main/mdo/settings.mdo</model>
               </models>
    
  • maven-settings/src/main/mdo/settings.mdo+13 0 modified
    @@ -633,6 +633,15 @@
                 of the mirror to repositories with a matching layout (apart from a matching id). Since Maven 3.
               </description>
             </field>
    +        <field>
    +          <name>blocked</name>
    +          <version>1.2.0+</version>
    +          <type>boolean</type>
    +          <defaultValue>false</defaultValue>
    +          <description>
    +            Whether this mirror should be blocked from any download request but fail the download process, explaining why.
    +          </description>
    +        </field>
           </fields>
           <codeSegments>
             <codeSegment>
    @@ -648,6 +657,10 @@
             sb.append( ",mirrorOf=" ).append( mirrorOf );
             sb.append( ",url=" ).append( this.url );
             sb.append( ",name=" ).append( this.name );
    +        if ( isBlocked() )
    +        {
    +            sb.append( ",blocked" );
    +        }
             sb.append( "]" );
             return sb.toString();
         }
    

Vulnerability mechanics

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

References

90

News mentions

0

No linked articles in our index yet.