VYPR
High severity7.8NVD Advisory· Published Apr 11, 2016· Updated May 6, 2026

CVE-2015-5349

CVE-2015-5349

Description

The CSV export in Apache LDAP Studio and Apache Directory Studio before 2.0.0-M10 does not properly escape field values, which might allow attackers to execute arbitrary commands by leveraging a crafted LDAP entry that is interpreted as a formula when imported into a spreadsheet.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.apache.directory.studio:org.apache.directory.studio.ldapbrowser.coreMaven
< 2.0.0.v20151221-M102.0.0.v20151221-M10

Affected products

27
  • cpe:2.3:a:apache:ldap_studio:0.6.0:*:*:*:*:*:*:*+ 3 more
    • cpe:2.3:a:apache:ldap_studio:0.6.0:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:ldap_studio:0.7.0:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:ldap_studio:0.8.0:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:ldap_studio:0.8.1:*:*:*:*:*:*:*
  • cpe:2.3:a:apache:directory_studio:1.0.0:*:*:*:*:*:*:*+ 22 more
    • cpe:2.3:a:apache:directory_studio:1.0.0:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:1.0.1:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:1.4.0:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:1.5.0:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:1.5.1:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:1.5.2:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:1.5.3:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:2.0.0:milestone1:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:2.0.0:milestone2:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:2.0.0:milestone3:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:1.1.0:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:1.1.0:rc1:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:1.1.0:rc2:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:1.2.0:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:1.2.0:rc1:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:1.3.0:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:1.3.0:rc1:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:2.0.0:milestone4:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:2.0.0:milestone5:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:2.0.0:milestone6:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:2.0.0:milestone7:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:2.0.0:milestone8:*:*:*:*:*:*
    • cpe:2.3:a:apache:directory_studio:2.0.0:milestone9:*:*:*:*:*:*

Patches

1
ac57a26fcb98

Escape spreadsheet formula in CSV export

https://github.com/apache/directory-studioStefan SeelmannDec 21, 2015via ghsa
6 files changed · +80 15
  • plugins/ldapbrowser.core/src/main/java/org/apache/directory/studio/ldapbrowser/core/jobs/ExportCsvRunnable.java+21 11 modified
    @@ -279,9 +279,8 @@ private static String recordToCsv( IBrowserConnection browserConnection, LdifCon
             StringBuffer sb = new StringBuffer();
             if ( exportDn )
             {
    -            sb.append( quoteCharacter );
    -            sb.append( record.getDnLine().getValueAsString() );
    -            sb.append( quoteCharacter );
    +            String value = record.getDnLine().getValueAsString();
    +            appendValue( quoteCharacter, sb, value );
     
                 if ( attributes == null || attributes.length > 0 )
                     sb.append( attributeDelimiter );
    @@ -295,14 +294,7 @@ private static String recordToCsv( IBrowserConnection browserConnection, LdifCon
                 if ( attributeMap.containsKey( oidString ) )
                 {
                     String value = attributeMap.get( oidString );
    -
    -                // escape
    -                value = value.replaceAll( quoteCharacter, quoteCharacter + quoteCharacter );
    -
    -                // always quote
    -                sb.append( quoteCharacter );
    -                sb.append( value );
    -                sb.append( quoteCharacter );
    +                appendValue( quoteCharacter, sb, value );
                 }
     
                 // delimiter
    @@ -318,6 +310,24 @@ private static String recordToCsv( IBrowserConnection browserConnection, LdifCon
         }
     
     
    +    private static void appendValue( String quoteCharacter, StringBuffer sb, String value )
    +    {
    +        // escape quote character
    +        value = value.replaceAll( quoteCharacter, quoteCharacter + quoteCharacter );
    +
    +        // prefix values starting with '=' with a single quote to avoid interpretation as formula
    +        if ( value.startsWith( "=" ) )
    +        {
    +            value = "'" + value;
    +        }
    +
    +        // always quote
    +        sb.append( quoteCharacter );
    +        sb.append( value );
    +        sb.append( quoteCharacter );
    +    }
    +
    +
         /**
          * Gets the attribute map.
          * 
    
  • plugins/ldapbrowser.core/src/main/java/org/apache/directory/studio/ldapbrowser/core/jobs/ExportXlsRunnable.java+14 4 modified
    @@ -46,6 +46,7 @@
     import org.apache.poi.hssf.usermodel.HSSFRow;
     import org.apache.poi.hssf.usermodel.HSSFSheet;
     import org.apache.poi.hssf.usermodel.HSSFWorkbook;
    +import org.apache.poi.ss.usermodel.Cell;
     import org.eclipse.core.runtime.Preferences;
     
     
    @@ -151,7 +152,7 @@ public void run( StudioProgressMonitor monitor )
             {
                 int cellNum = 0;
                 attributeNameMap.put( "dn", cellNum ); //$NON-NLS-1$
    -            headerRow.createCell( cellNum ).setCellValue( "dn" ); //$NON-NLS-1$
    +            createStringCell( headerRow, cellNum ).setCellValue( "dn" ); //$NON-NLS-1$
             }
     
             // max export
    @@ -289,7 +290,7 @@ private static void recordToHSSFRow( IBrowserConnection browserConnection, LdifC
             HSSFRow row = sheet.createRow( sheet.getLastRowNum() + 1 );
             if ( exportDn )
             {
    -            HSSFCell cell = row.createCell( 0 );
    +            HSSFCell cell = createStringCell(row, 0 );
                 cell.setCellValue( record.getDnLine().getValueAsString() );
             }
             for ( String attributeName : attributeMap.keySet() )
    @@ -300,17 +301,26 @@ private static void recordToHSSFRow( IBrowserConnection browserConnection, LdifC
                 {
                     int cellNum = headerRowAttributeNameMap.size();
                     headerRowAttributeNameMap.put( attributeName, new Integer( cellNum ) );
    -                HSSFCell cell = headerRow.createCell( cellNum );
    +                HSSFCell cell = createStringCell( headerRow, cellNum );
                     cell.setCellValue( attributeName );
                 }
     
                 if ( headerRowAttributeNameMap.containsKey( attributeName ) )
                 {
                     int cellNum = headerRowAttributeNameMap.get( attributeName ).shortValue();
    -                HSSFCell cell = row.createCell( cellNum );
    +                HSSFCell cell = createStringCell( row, cellNum );
                     cell.setCellValue( value );
                 }
             }
     
         }
    +
    +
    +    private static HSSFCell createStringCell( HSSFRow row, int cellNum )
    +    {
    +        HSSFCell cell = row.createCell( cellNum );
    +        cell.setCellType( Cell.CELL_TYPE_STRING );
    +        return cell;
    +    }
    +
     }
    
  • tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/bots/BrowserViewBot.java+7 0 modified
    @@ -137,6 +137,13 @@ public ExportWizardBot openExportDsmlWizard()
         }
     
     
    +    public ExportWizardBot openExportCsvWizard()
    +    {
    +        ContextMenuHelper.clickContextMenu( browserBot.getTree(), "Export", "CSV Export..." );
    +        return new ExportWizardBot( ExportWizardBot.EXPORT_CSV_TITLE );
    +    }
    +
    +
         public ImportWizardBot openImportLdifWizard()
         {
             ContextMenuHelper.clickContextMenu( browserBot.getTree(), "Import", "LDIF Import..." );
    
  • tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/bots/ExportWizardBot.java+7 0 modified
    @@ -31,6 +31,7 @@ public class ExportWizardBot extends WizardBot
     {
         public static final String EXPORT_LDIF_TITLE = "LDIF Export";
         public static final String EXPORT_DSML_TITLE = "DSML Export";
    +    public static final String EXPORT_CSV_TITLE = "CSV Export";
         private String title;
     
     
    @@ -53,6 +54,12 @@ public boolean isVisible()
         }
     
     
    +    public void typeReturningAttributes( String returningAttributes )
    +    {
    +        bot.comboBoxWithLabel( "Returning Attributes:" ).setText( returningAttributes );
    +    }
    +
    +
         public void typeFile( String file )
         {
             bot.comboBox().setText( file );
    
  • tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/ImportExportTest.java+30 0 modified
    @@ -266,4 +266,34 @@ public void testImportDontUptateUI() throws Exception
             assertEquals( "Only 2 event firings expected when importing LDIF.", 2, fireCount );
         }
     
    +
    +    /**
    +     * Export to CSV and checks that spreadsheet formulas are prefixed with an apostrophe.
    +     */
    +    @Test
    +    public void testExportCsvShouldPrefixFormulaWithApostrophe() throws Exception
    +    {
    +        URL url = Platform.getInstanceLocation().getURL();
    +        final String file = url.getFile() + "ImportExportTest.csv";
    +        System.out.println( file );
    +
    +        browserViewBot.selectEntry( "DIT", "Root DSE", "ou=system", "ou=users", "cn=Wolfgang K\u00f6lbel" );
    +
    +        // export LDIF
    +        ExportWizardBot wizardBot = browserViewBot.openExportCsvWizard();
    +        assertTrue( wizardBot.isVisible() );
    +        wizardBot.typeReturningAttributes( "cn, description" );
    +        wizardBot.clickNextButton();
    +        wizardBot.typeFile( file );
    +        wizardBot.clickFinishButton();
    +        wizardBot.waitTillExportFinished( file, 80 ); // is actually 86 bytes
    +
    +        List<String> lines = FileUtils.readLines( new File( file ) );
    +        // verify that the first line is header
    +        assertEquals( "dn,cn,description", lines.get( 0 ) );
    +        // verify that the second line is actual content and the formula is prefixed with an apostrophe
    +        assertEquals( "\"cn=Wolfgang K\u00f6lbel,ou=users,ou=system\",\"Wolfgang K\u00f6lbel\",\"'=1+1\"",
    +            lines.get( 1 ) );
    +    }
    +
     }
    
  • tests/test.integration.ui/src/main/resources/org/apache/directory/studio/test/integration/ui/ImportExportTest.ldif+1 0 modified
    @@ -22,4 +22,5 @@ objectClass: inetOrgPerson
     objectClass: top
     cn:: V29sZmdhbmcgS8O2bGJlbA==
     sn:: S8O2bGJlbA==
    +description: =1+1
     
    

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

8

News mentions

0

No linked articles in our index yet.