{"record":{"id":"17fa486b85a61483","repo":"apache/cordova-android","slug":"destination-dest-for-source-file-src-is","errorCode":null,"errorMessage":"Destination \"${dest}\" for source file \"${src}\" is located outside the project","messagePattern":"Destination \"(.+?)\" for source file \"(.+?)\" is located outside the project","errorType":"validation","errorClass":"CordovaError","httpStatus":null,"severity":"error","filePath":"lib/pluginHandlers.js","lineNumber":220,"sourceCode":"        return handlers[type].uninstall;\n    }\n\n    events.emit('verbose', '<' + type + '> is not supported for android plugins');\n};\n\nfunction copyFile (plugin_dir, src, project_dir, dest, link) {\n    src = path.resolve(plugin_dir, src);\n    if (!fs.existsSync(src)) throw new CordovaError('\"' + src + '\" not found!');\n\n    // check that src path is inside plugin directory\n    const real_path = fs.realpathSync(src);\n    const real_plugin_path = fs.realpathSync(plugin_dir);\n    if (!isPathInside(real_path, real_plugin_path)) { throw new CordovaError('File \"' + src + '\" is located outside the plugin directory \"' + plugin_dir + '\"'); }\n\n    dest = path.resolve(project_dir, dest);\n\n    // check that dest path is located in project directory\n    if (!isPathInside(dest, project_dir)) { throw new CordovaError('Destination \"' + dest + '\" for source file \"' + src + '\" is located outside the project'); }\n\n    fs.mkdirSync(path.dirname(dest), { recursive: true });\n    if (link) {\n        symlinkFileOrDirTree(src, dest);\n    } else {\n        fs.cpSync(src, dest, { recursive: true });\n    }\n}\n\n// Same as copy file but throws error if target exists\nfunction copyNewFile (plugin_dir, src, project_dir, dest, link) {\n    const target_path = path.resolve(project_dir, dest);\n    if (fs.existsSync(target_path)) { throw new CordovaError('\"' + target_path + '\" already exists!'); }\n\n    copyFile(plugin_dir, src, project_dir, dest, !!link);\n}\n\nfunction symlinkFileOrDirTree (src, dest) {","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/apache/cordova-android/blob/7c1e190064e349ffa4bbc6ac37b77cd773e4dbd3/lib/pluginHandlers.js#L202-L238","documentation":"The destination-side guard in copyFile: the resolved destination must be inside the project directory. A target/target-dir attribute containing ../ or an absolute path resolves outside platforms/android and the copy is refused with this CordovaError, protecting the filesystem from plugins writing outside the Cordova project.","triggerScenarios":"A plugin.xml element like <source-file src=\"x.java\" target-dir=\"../../somewhere\"/> or a target attribute resolving outside projectDir; also resource-file target=\"res/../../etc/hosts\"-style paths. Thrown during `cordova plugin add` / `cordova prepare`.","commonSituations":"Plugin author mistakenly writes an install-absolute path (target-dir=\"/src/com/x\") which path.resolve treats as absolute and escapes the project; ported iOS-style target paths; malicious or buggy third-party plugin.","solutions":["Change target-dir/target to a path relative to the Android project root without leading slash or ../, e.g. target-dir=\"src/com/example/plugin\"","Verify what the project root is for the element type (source-file: app/src/main/java...; resource-file: app/src/main/res...)","Treat this error in a third-party plugin as a red flag: inspect its plugin.xml before working around it"],"exampleFix":"<!-- before -->\n<resource-file src=\"hosts\" target=\"/etc/hosts\" />\n\n<!-- after -->\n<resource-file src=\"hosts\" target=\"app/src/main/res/raw/hosts\" />","handlingStrategy":"validation","validationCode":"// target-dir/target must be relative and must not escape the project\nconst safe = t => !path.isAbsolute(t) && !t.split('/').includes('..');\nif (!safe(targetDirAttr)) throw new Error('target escapes the Cordova project and will be rejected');","typeGuard":null,"tryCatchPattern":"try { await cordova.plugin('add', p); } catch (e) {\n  if (/located outside the project/.test(e.message)) { /* fix target/target-dir to a project-relative path */ }\n}","preventionTips":["Write target-dir relative to the Android platform project (no leading /)","Treat absolute targets in third-party plugins as malicious and inspect them"],"tags":["cordova","cordova-android","plugin-xml","security","path-traversal"],"backgroundTag":"path-traversal-blocked","analyzedSha":"7c1e190064e349ffa4bbc6ac37b77cd773e4dbd3","analyzedAt":"2026-08-22T04:57:58.868Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}